diff --git a/Jamfile b/Jamfile
new file mode 100644
index 0000000000..489c9a4c93
--- /dev/null
+++ b/Jamfile
@@ -0,0 +1,13 @@
+# Boost.Random Library Jamfile
+#
+# Copyright (c) 2010
+# Steven Watanabe
+#
+# Use, modification, and distribution are subject to the
+# Boost Software License, Version 1.0. (See accompanying file
+# LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+project libs/random ;
+
+# please order by name to ease maintenance
+build-project test ;
diff --git a/build/Jamfile.v2 b/build/Jamfile.v2
deleted file mode 100644
index b4e9ceae30..0000000000
--- a/build/Jamfile.v2
+++ /dev/null
@@ -1,18 +0,0 @@
-# Jamfile.v2
-#
-# Copyright (c) 2010
-# Steven Watanabe
-#
-# Distributed under the Boost Software License, Version 1.0. (See
-# accompanying file LICENSE_1_0.txt or copy at
-# http://www.boost.org/LICENSE_1_0.txt)
-
-project /boost/random
- : source-location ../src
- : requirements shared:BOOST_RANDOM_DYN_LINK
- : usage-requirements shared:BOOST_RANDOM_DYN_LINK
-;
-
-lib boost_random : [ glob *.cpp ] /boost//system ;
-
-boost-install boost_random ;
diff --git a/include/boost/random/detail/random_device_bcrypt.hpp b/include/boost/random/detail/random_device_bcrypt.hpp
new file mode 100644
index 0000000000..adf3b105fc
--- /dev/null
+++ b/include/boost/random/detail/random_device_bcrypt.hpp
@@ -0,0 +1,110 @@
+/* boost random/detail/random_device_bcrypt header file
+*
+* Copyright 2017 James E. King, III
+*
+* Distributed under the Boost Software License, Version 1.0. (See
+* accompanying file LICENSE_1_0.txt or copy at
+* http://www.boost.org/LICENSE_1_0.txt)
+*
+* $Id$
+*
+* Revision history
+* 2017-09-14 initial bcrypt implementation
+*/
+
+#ifndef BOOST_RANDOM_DETAIL_RANDOM_DEVICE_BCRYPT
+#define BOOST_RANDOM_DETAIL_RANDOM_DEVICE_BCRYPT
+
+#include
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+#if defined(BOOST_WINDOWS)
+#include
+
+#if !(BOOST_WINAPI_PARTITION_DESKTOP || BOOST_WINAPI_PARTITION_SYSTEM) || defined(BOOST_RANDOM_DEVICE_FORCE_BCRYPT)
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#if !defined(BOOST_RANDOM_DEVICE_NO_LIB)
+# define BOOST_LIB_NAME "bcrypt"
+# define BOOST_AUTO_LINK_NOMANGLE
+# include
+#endif
+
+namespace boost {
+namespace random {
+namespace detail {
+
+template
+class random_device_bcrypt : private noncopyable
+{
+public:
+ typedef Entropy result_type;
+
+ random_device_bcrypt(const std::string& token = std::string())
+ : hProv_(NULL)
+ {
+ boost::ignore_unused(token);
+ boost::winapi::NTSTATUS_ status =
+ boost::winapi::BCryptOpenAlgorithmProvider(
+ &hProv_,
+ boost::winapi::BCRYPT_RNG_ALGORITHM_,
+ NULL,
+ 0);
+
+ if (status)
+ {
+ BOOST_THROW_EXCEPTION(system::system_error(
+ status, system::system_category(), "BCryptOpenAlgorithmProvider"));
+ }
+ }
+
+ ~random_device_bcrypt() BOOST_NOEXCEPT
+ {
+ if (hProv_)
+ {
+ ignore_unused(boost::winapi::BCryptCloseAlgorithmProvider(hProv_, 0));
+ }
+ }
+
+ result_type operator()()
+ {
+ result_type result;
+
+ boost::winapi::NTSTATUS_ status =
+ boost::winapi::BCryptGenRandom(
+ hProv_,
+ reinterpret_cast(&result),
+ sizeof(result),
+ 0);
+
+ if (status)
+ {
+ BOOST_THROW_EXCEPTION(system::system_error(
+ status, system::system_category(), "BCryptGenRandom"));
+ }
+
+ return result;
+ }
+
+private:
+ boost::winapi::BCRYPT_ALG_HANDLE_ hProv_;
+};
+
+} // detail
+} // random
+} // boost
+
+#endif // !(BOOST_WINAPI_PARTITION_DESKTOP || BOOST_WINAPI_PARTITION_SYSTEM) || defined(BOOST_RANDOM_DEVICE_FORCE_BCRYPT)
+#endif // BOOST_WINDOWS
+#endif // BOOST_RANDOM_DETAIL_RANDOM_DEVICE_BCRYPT
diff --git a/include/boost/random/detail/random_device_file.hpp b/include/boost/random/detail/random_device_file.hpp
new file mode 100644
index 0000000000..71a2c311e8
--- /dev/null
+++ b/include/boost/random/detail/random_device_file.hpp
@@ -0,0 +1,100 @@
+/* boost random/detail/random_device_file header file
+*
+* Copyright Jens Maurer 2000
+* Copyright 2007 Andy Tompkins.
+* Copyright Steven Watanabe 2010-2011
+* Copyright 2017 James E. King, III
+*
+* Distributed under the Boost Software License, Version 1.0. (See
+* accompanying file LICENSE_1_0.txt or copy at
+* http://www.boost.org/LICENSE_1_0.txt)
+*
+* $Id$
+*
+* Revision history
+* 2017-09-14 urandom implementation moved here
+*/
+
+#ifndef BOOST_RANDOM_DETAIL_RANDOM_DEVICE_FILE
+#define BOOST_RANDOM_DETAIL_RANDOM_DEVICE_FILE
+
+#include
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+#if !defined(BOOST_WINDOWS)
+
+#include
+#include
+#include
+#include
+#include
+#include // open
+#include
+#include
+#include
+#if defined(BOOST_HAS_UNISTD_H)
+#include
+#endif
+
+namespace boost {
+namespace random {
+namespace detail {
+
+template
+class random_device_file : private noncopyable
+{
+public:
+ typedef Entropy result_type;
+
+ random_device_file(const std::string& token = std::string())
+ : fd_(0)
+ {
+ fd_ = open(token.empty() ? "/dev/urandom" : token.c_str(), O_RDONLY);
+
+ if (-1 == fd_)
+ {
+ BOOST_THROW_EXCEPTION(system::system_error(
+ errno, system::system_category(), "open " + std::string(token.empty() ? "/dev/urandom" : token.c_str())));
+ }
+ }
+
+ ~random_device_file() BOOST_NOEXCEPT
+ {
+ if (fd_)
+ {
+ ignore_unused(close(fd_));
+ }
+ }
+
+ result_type operator()()
+ {
+ result_type result;
+ size_t offset = 0;
+ do
+ {
+ ssize_t sz = read(fd_, reinterpret_cast(&result) + offset, sizeof(result) - offset);
+
+ if (sz < 1)
+ {
+ BOOST_THROW_EXCEPTION(system::system_error(
+ errno, system::system_category(), "read"));
+ }
+ offset += sz;
+ } while (offset < sizeof(result));
+
+ return result;
+ }
+
+private:
+ int fd_;
+};
+
+} // detail
+} // random
+} // boost
+
+#endif // !defined(BOOST_WINDOWS)
+#endif // BOOST_RANDOM_DETAIL_RANDOM_DEVICE_FILE
diff --git a/include/boost/random/detail/random_device_wincrypt.hpp b/include/boost/random/detail/random_device_wincrypt.hpp
new file mode 100644
index 0000000000..e9face076b
--- /dev/null
+++ b/include/boost/random/detail/random_device_wincrypt.hpp
@@ -0,0 +1,140 @@
+/* boost random/detail/random_device_wincrypt header file
+ *
+ * Copyright Jens Maurer 2000
+ * Copyright 2007 Andy Tompkins.
+ * Copyright Steven Watanabe 2010-2011
+ * Copyright 2017 James E. King, III
+ *
+ * Distributed under the Boost Software License, Version 1.0. (See
+ * accompanying file LICENSE_1_0.txt or copy at
+ * http://www.boost.org/LICENSE_1_0.txt)
+ *
+ * $Id$
+ *
+ * Revision history
+ * 2017-09-14 wincrypt implementation moved here
+ */
+
+#ifndef BOOST_RANDOM_DETAIL_RANDOM_DEVICE_WINCRYPT
+#define BOOST_RANDOM_DETAIL_RANDOM_DEVICE_WINCRYPT
+
+#include
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+#if defined(BOOST_WINDOWS)
+#include
+
+#if BOOST_WINAPI_PARTITION_DESKTOP || BOOST_WINAPI_PARTITION_SYSTEM
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#if !defined(BOOST_RANDOM_DEVICE_NO_LIB)
+# if defined(_WIN32_WCE)
+# define BOOST_LIB_NAME "coredll"
+# else
+# define BOOST_LIB_NAME "advapi32"
+# endif
+# define BOOST_AUTO_LINK_NOMANGLE
+# include
+#endif
+
+namespace boost {
+namespace random {
+namespace detail {
+
+template
+class random_device_wincrypt : private noncopyable
+{
+public:
+ typedef Entropy result_type;
+
+ random_device_wincrypt(const std::string& token = std::string())
+ : hProv_(NULL)
+ {
+#if defined(BOOST_NO_ANSI_APIS)
+ // Without ANSI APIs, the token is ignored
+ ignore_unused(token);
+ if (!boost::winapi::CryptAcquireContextW(
+ &hProv_,
+ NULL,
+ NULL,
+ boost::winapi::PROV_RNG_,
+ boost::winapi::CRYPT_VERIFYCONTEXT_ | boost::winapi::CRYPT_SILENT_))
+ {
+ BOOST_THROW_EXCEPTION(system::system_error(
+ boost::winapi::GetLastError(), system::system_category(), "CryptAcquireContextW"));
+ }
+#else
+ // With ANSI APIs, the behavior is backwards compatible to previous releases
+ boost::winapi::CHAR_ buffer[256];
+ boost::winapi::DWORD_ type;
+ boost::winapi::DWORD_ len;
+ std::string provider = token.empty() ? "Microsoft Base Cryptographic Provider v1.0" : token;
+
+ // Find the type of a specific provider
+ for (boost::winapi::DWORD_ i = 0; ; ++i)
+ {
+ len = sizeof(buffer);
+ if (!boost::winapi::CryptEnumProvidersA(i, NULL, 0, &type, buffer, &len))
+ {
+ BOOST_THROW_EXCEPTION(system::system_error(
+ boost::winapi::GetLastError(), system::system_category(), "CryptEnumProvidersA"));
+ }
+ if (buffer == provider) {
+ break;
+ }
+ }
+
+ if (!boost::winapi::CryptAcquireContextA(
+ &hProv_,
+ NULL,
+ provider.c_str(),
+ type,
+ boost::winapi::CRYPT_VERIFYCONTEXT_ | boost::winapi::CRYPT_SILENT_))
+ {
+ BOOST_THROW_EXCEPTION(system::system_error(
+ boost::winapi::GetLastError(), system::system_category(), "CryptAcquireContextA"));
+ }
+#endif
+ }
+
+ ~random_device_wincrypt() BOOST_NOEXCEPT
+ {
+ if (hProv_)
+ {
+ ignore_unused(boost::winapi::CryptReleaseContext(hProv_, 0));
+ }
+ }
+
+ result_type operator()()
+ {
+ result_type result;
+ if (!boost::winapi::CryptGenRandom(hProv_, sizeof(result), boost::winapi::detail::cast_ptr(&result)))
+ {
+ BOOST_THROW_EXCEPTION(system::system_error(
+ boost::winapi::GetLastError(), system::system_category(), "CryptGenRandom"));
+ }
+ return result;
+ }
+
+private:
+ boost::winapi::HCRYPTPROV_ hProv_;
+};
+
+} // detail
+} // random
+} // boost
+
+#endif // BOOST_WINAPI_PARTITION_DESKTOP || BOOST_WINAPI_PARTITION_SYSTEM
+#endif // BOOST_WINDOWS
+#endif // BOOST_RANDOM_DETAIL_RANDOM_DEVICE_WINCRYPT
diff --git a/include/boost/random/random_device.hpp b/include/boost/random/random_device.hpp
index 8f3903c953..9bb1dc0cd7 100644
--- a/include/boost/random/random_device.hpp
+++ b/include/boost/random/random_device.hpp
@@ -1,7 +1,10 @@
/* boost random/random_device.hpp header file
*
* Copyright Jens Maurer 2000
+ * Copyright 2007 Andy Tompkins.
* Copyright Steven Watanabe 2010-2011
+ * Copyright 2017 James E. King, III
+ *
* Distributed under the Boost Software License, Version 1.0. (See
* accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
@@ -10,19 +13,21 @@
*
* Revision history
* 2000-02-18 Portability fixes (thanks to Beman Dawes)
+ * 2017-09-04 Made header-only, configurable entropy size, UWP compatible
*/
// See http://www.boost.org/libs/random for documentation.
-
#ifndef BOOST_RANDOM_RANDOM_DEVICE_HPP
#define BOOST_RANDOM_RANDOM_DEVICE_HPP
-#include
#include
-#include
-#include
-#include // force autolink to find Boost.System
+#include
+#include
+
+#include
+#include
+#include
namespace boost {
namespace random {
@@ -50,93 +55,123 @@ namespace random {
* on all platforms.
* @endxmlnote
*
- * Implementation Note for Linux
+ * Implementation Note for Unix
*
- * On the Linux operating system, token is interpreted as a filesystem
+ * On Unix operating systems, the token is interpreted as a filesystem
* path. It is assumed that this path denotes an operating system
* pseudo-device which generates a stream of non-deterministic random
* numbers. The pseudo-device should never signal an error or end-of-file.
- * Otherwise, @c std::ios_base::failure is thrown. By default,
- * \random_device uses the /dev/urandom pseudo-device to retrieve
+ *
+ * By default, \random_device uses the /dev/urandom pseudo-device to retrieve
* the random numbers. Another option would be to specify the /dev/random
* pseudo-device, which blocks on reads if the entropy pool has no more
* random bits available.
*
* Implementation Note for Windows
+ *
+ * When targeting Windows Desktop or System applications with UWP, or when
+ * not using UWP (older SDKs), the traditional wincrypt provider is used to
+ * get entropy for backwards compatibility with the previous implementation.
+ * This ensures anyone who has developed and use their own crypto provider
+ * for random number generation can still use it. The optional token can
+ * be the name of a wincrypt provider. If no token is specified, the default
+ * MS_DEF_PROV_A is used. If BOOST_NO_ANSI_APIS is defined, the token is ignored.
+ *
+ * For all other windows targets, for example Windows Store UWP targets,
+ * bcrypt is used to acquire entropy. In these cases, the token is ignored.
+ * There are some platform/SDK combinations where it is not possible to have
+ * a random device on Windows - for example Windows SDK 8.x with a non-desktop
+ * target, since bcrypt is specified as desktop-only in SDK 8.x and expanded to
+ * other partitions in SDK 10.x.
+ *
+ * Compile-Time Definitions
+ *
+ * [Windows] To force use of bcrypt over wincrypt on desktop platforms,
+ * define BOOST_RANDOM_DEVICE_FORCE_BCRYPT
+ *
+ * [Windows] To disable automatic link libraries being added by providers,
+ * define BOOST_RANDOM_DEVICE_NO_LIB
+ *
+ * [All] To prevent the automatic definition of boost::random::random_device,
+ * define BOOST_RANDOM_DEVICE_NO_DEFAULT_IMPL
+ *
+ * Exceptions
*
- * On the Windows operating system, token is interpreted as the name
- * of a cryptographic service provider. By default \random_device uses
- * MS_DEF_PROV.
+ * Errors will result in a boost::system::system_error exception.
*
- * Performance
+ * Concepts
*
- * The test program
- * nondet_random_speed.cpp measures the execution times of the
- * random_device.hpp implementation of the above algorithms in a tight
- * loop. The performance has been evaluated on an
- * Intel(R) Core(TM) i7 CPU Q 840 \@ 1.87GHz, 1867 Mhz with
- * Visual C++ 2010, Microsoft Windows 7 Professional and with gcc 4.4.5,
- * Ubuntu Linux 2.6.35-25-generic.
+ * A RandomDeviceProvider must:
+ * - provide a result_type type definition
+ * - provide an operator() implementation returning a result_type
*
- *
- * | Platform | time per invocation [microseconds] |
- * | Windows | 2.9 |
- * | Linux | 1.7 |
- *
+ * A UniformRandomNumberGenerator must (as documented):
+ * - provide a min()
+ * - provide a max()
+ * - provide an operator()
*
- * The measurement error is estimated at +/- 1 usec.
+ * The common parts of a UniformRandomNumberGenerator are provided by
+ * basic_random_device.
*/
-class random_device : private noncopyable
+template
+class basic_random_device : public RandomDeviceProvider
{
public:
- typedef unsigned int result_type;
+ basic_random_device(const std::string& token = std::string())
+ : RandomDeviceProvider(token)
+ {
+ }
+
+ typedef typename RandomDeviceProvider::result_type result_type;
BOOST_STATIC_CONSTANT(bool, has_fixed_range = false);
/** Returns the smallest value that the \random_device can produce. */
- static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () { return 0; }
- /** Returns the largest value that the \random_device can produce. */
- static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () { return ~0u; }
-
- /** Constructs a @c random_device, optionally using the default device. */
- BOOST_RANDOM_DECL random_device();
- /**
- * Constructs a @c random_device, optionally using the given token as an
- * access specification (for example, a URL) to some implementation-defined
- * service for monitoring a stochastic process.
- */
- BOOST_RANDOM_DECL explicit random_device(const std::string& token);
+ static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION ()
+ {
+ return (std::numeric_limits::min)();
+ }
- BOOST_RANDOM_DECL ~random_device();
+ /** Returns the largest value that the \random_device can produce. */
+ static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION()
+ {
+ return (std::numeric_limits::max)();
+ }
/**
- * Returns: An entropy estimate for the random numbers returned by
- * operator(), in the range min() to log2( max()+1). A deterministic
- * random number generator (e.g. a pseudo-random number engine)
- * has entropy 0.
- *
- * Throws: Nothing.
+ * Fills a range with random values.
+ * Throws boost::system::system_error if an error occurs.
*/
- BOOST_RANDOM_DECL double entropy() const;
- /** Returns a random value in the range [min, max]. */
- BOOST_RANDOM_DECL unsigned int operator()();
-
- /** Fills a range with random 32-bit values. */
template
void generate(Iter begin, Iter end)
{
- for(; begin != end; ++begin) {
+ for(; begin != end; ++begin)
+ {
*begin = (*this)();
}
}
-
-private:
- class impl;
- impl * pimpl;
};
+//
+// Automatically select a default platform specific implementation
+//
+
+#if !defined(BOOST_RANDOM_DEVICE_NO_DEFAULT_IMPL)
+#if defined(BOOST_WINDOWS)
+#if (BOOST_WINAPI_PARTITION_DESKTOP || BOOST_WINAPI_PARTITION_SYSTEM) && !defined(BOOST_RANDOM_DEVICE_FORCE_BCRYPT)
+ typedef basic_random_device > random_device;
+#else
+ typedef basic_random_device > random_device;
+#endif
+#else
+ typedef basic_random_device > random_device;
+#endif
+#endif
+
} // namespace random
+#if !defined(BOOST_RANDOM_DEVICE_NO_DEFAULT_IMPL)
using random::random_device;
+#endif
} // namespace boost
diff --git a/src/random_device.cpp b/src/random_device.cpp
deleted file mode 100644
index 8ec3863107..0000000000
--- a/src/random_device.cpp
+++ /dev/null
@@ -1,250 +0,0 @@
-/* boost random_device.cpp implementation
- *
- * Copyright Jens Maurer 2000
- * Copyright Steven Watanabe 2010-2011
- * Distributed under the Boost Software License, Version 1.0. (See
- * accompanying file LICENSE_1_0.txt or copy at
- * http://www.boost.org/LICENSE_1_0.txt)
- *
- * $Id$
- *
- */
-
-#define BOOST_RANDOM_SOURCE
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#if !defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION) && !BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
-// A definition is required even for integral static constants
-const bool boost::random::random_device::has_fixed_range;
-#endif
-
-// WinRT target.
-#if !defined(BOOST_RANDOM_WINDOWS_RUNTIME)
-# if defined(__cplusplus_winrt)
-# include
-# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
-# define BOOST_RANDOM_WINDOWS_RUNTIME 1
-# endif
-# endif
-#endif
-
-#if defined(BOOST_WINDOWS)
-
-#if !defined(BOOST_RANDOM_WINDOWS_RUNTIME)
-#include
-#include
-#include // std::invalid_argument
-#else
-using namespace Platform;
-using namespace Windows::Security::Cryptography;
-#endif
-
-#define BOOST_AUTO_LINK_NOMANGLE
-#define BOOST_LIB_NAME "Advapi32"
-#include
-
-#ifdef __MINGW32__
-
-extern "C" {
-
-// mingw's wincrypt.h appears to be missing some things
-WINADVAPI
-BOOL
-WINAPI
-CryptEnumProvidersA(
- DWORD dwIndex,
- DWORD *pdwReserved,
- DWORD dwFlags,
- DWORD *pdwProvType,
- LPSTR szProvName,
- DWORD *pcbProvName
- );
-
-}
-
-#endif
-
-namespace {
-#if !defined(BOOST_RANDOM_WINDOWS_RUNTIME)
-const char * const default_token = MS_DEF_PROV_A;
-#else
-const char * const default_token = "";
-#endif
-}
-
-class boost::random::random_device::impl
-{
-public:
- impl(const std::string & token) : provider(token) {
-#if !defined(BOOST_RANDOM_WINDOWS_RUNTIME)
- char buffer[80];
- DWORD type;
- DWORD len;
-
- // Find the type of a specific provider
- for(DWORD i = 0; ; ++i) {
- len = sizeof(buffer);
- if(!CryptEnumProvidersA(i, NULL, 0, &type, buffer, &len)) {
- if (GetLastError() == ERROR_NO_MORE_ITEMS) break;
- continue;
- }
- if(buffer == provider) {
- break;
- }
- }
-
- if(!CryptAcquireContextA(&hProv, NULL, provider.c_str(), type,
- CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
- error("Could not acquire CSP context");
- }
-#endif
- }
-
-#if !defined(BOOST_RANDOM_WINDOWS_RUNTIME)
- ~impl() {
- if(!CryptReleaseContext(hProv, 0)) error("Could not release CSP context");
- }
-#endif
-
- unsigned int next() {
- unsigned int result;
-
-#if !defined(BOOST_RANDOM_WINDOWS_RUNTIME)
- if(!CryptGenRandom(hProv, sizeof(result),
- static_cast(static_cast(&result)))) {
- error("error while reading");
- }
-#else
- auto buffer = CryptographicBuffer::GenerateRandom(sizeof(result));
- auto data = ref new Array(buffer->Length);
- CryptographicBuffer::CopyToByteArray(buffer, &data);
- memcpy(&result, data->begin(), data->end() - data->begin());
-#endif
-
- return result;
- }
-
-private:
-#if !defined(BOOST_RANDOM_WINDOWS_RUNTIME)
- void error(const char * msg) {
- DWORD error_code = GetLastError();
- boost::throw_exception(
- boost::system::system_error(
- error_code, boost::system::system_category(),
- std::string("boost::random_device: ") + msg +
- " Cryptographic Service Provider " + provider));
- }
- HCRYPTPROV hProv;
-#endif
- const std::string provider;
-};
-
-#else
-
-namespace {
-// the default is the unlimited capacity device, using some secure hash
-// try "/dev/random" for blocking when the entropy pool has drained
-const char * const default_token = "/dev/urandom";
-}
-
-/*
- * This uses the POSIX interface for unbuffered reading.
- * Using buffered std::istream would consume entropy which may
- * not actually be used. Entropy is a precious good we avoid
- * wasting.
- */
-
-#if defined(__GNUC__) && defined(_CXXRT_STD_NAME)
-// I have severe difficulty to get the POSIX includes to work with
-// -fhonor-std and Dietmar Kuhl's standard C++ library. Hack around that
-// problem for now.
-extern "C" {
-static const int O_RDONLY = 0;
-extern int open(const char *__file, int __oflag, ...);
-extern int read(int __fd, __ptr_t __buf, size_t __nbytes);
-extern int close(int __fd);
-}
-#else
-#include
-#include
-#include // open
-#include // read, close
-#endif
-
-#include // errno
-#include // strerror
-#include // std::invalid_argument
-
-
-class boost::random::random_device::impl
-{
-public:
- impl(const std::string & token) : path(token) {
- fd = open(token.c_str(), O_RDONLY);
- if(fd < 0)
- error("cannot open");
- }
-
- ~impl() { if(close(fd) < 0) error("could not close"); }
-
- unsigned int next() {
- unsigned int result;
- std::size_t offset = 0;
- do {
- long sz = read(fd, reinterpret_cast(&result) + offset, sizeof(result) - offset);
- if(sz == -1)
- error("error while reading");
- else if(sz == 0) {
- errno = 0;
- error("EOF while reading");
- }
- offset += sz;
- } while(offset < sizeof(result));
- return result;
- }
-
-private:
- void error(const char * msg) {
- int error_code = errno;
- boost::throw_exception(
- boost::system::system_error(
- error_code, boost::system::system_category(),
- std::string("boost::random_device: ") + msg +
- " random-number pseudo-device " + path));
- }
- const std::string path;
- int fd;
-};
-
-#endif // BOOST_WINDOWS
-
-BOOST_RANDOM_DECL boost::random::random_device::random_device()
- : pimpl(new impl(default_token))
-{}
-
-BOOST_RANDOM_DECL boost::random::random_device::random_device(const std::string& token)
- : pimpl(new impl(token))
-{}
-
-BOOST_RANDOM_DECL boost::random_device::~random_device()
-{
- delete pimpl;
-}
-
-BOOST_RANDOM_DECL double boost::random_device::entropy() const
-{
- return 10;
-}
-
-BOOST_RANDOM_DECL unsigned int boost::random_device::operator()()
-{
- return pimpl->next();
-}
diff --git a/test/Jamfile.v2 b/test/Jamfile.v2
index 25424bc671..7219eeed26 100644
--- a/test/Jamfile.v2
+++ b/test/Jamfile.v2
@@ -13,9 +13,8 @@ project /boost/random/test : requirements msvc:_SCL_SECURE_NO_W
run test_const_mod.cpp /boost//unit_test_framework ;
run test_generate_canonical.cpp /boost//unit_test_framework ;
run test_random_number_generator.cpp /boost//unit_test_framework ;
+run test_random_device.cpp /boost//unit_test_framework ;
run ../example/random_demo.cpp ;
-run test_random_device.cpp /boost//random : : : static : test_random_device ;
-run test_random_device.cpp /boost//random : : : shared : test_random_device_dll ;
run test_minstd_rand0.cpp /boost//unit_test_framework ;
run test_minstd_rand.cpp /boost//unit_test_framework ;
@@ -125,7 +124,6 @@ run test_hyperexponential.cpp ;
run test_hyperexponential_distribution.cpp /boost//unit_test_framework ;
# run nondet_random_speed.cpp ;
-# run random_device.cpp ;
# run random_speed.cpp ;
# run statistic_tests.cpp ;
diff --git a/test/test_random_device.cpp b/test/test_random_device.cpp
index 2f9e61c76e..def25b1136 100644
--- a/test/test_random_device.cpp
+++ b/test/test_random_device.cpp
@@ -8,22 +8,66 @@
* $Id$
*/
-#include
+#define BOOST_TEST_MAIN
+#include
+#include
-#include
-#include
+#include
+#include
-int test_main(int, char**) {
+BOOST_AUTO_TEST_CASE(random_device)
+{
boost::random_device rng;
- double entropy = rng.entropy();
- BOOST_CHECK_GE(entropy, 0);
- for(int i = 0; i < 100; ++i) {
+
+ BOOST_CHECK_EQUAL(0u, rng.min());
+ BOOST_CHECK_EQUAL(~0u, rng.max());
+
+ for (int i = 0; i < 100; ++i)
+ {
boost::random_device::result_type val = rng();
- BOOST_CHECK_GE(val, (rng.min)());
- BOOST_CHECK_LE(val, (rng.max)());
+ BOOST_CHECK_GE(val, 0u);
+ BOOST_CHECK_LE(val, ~0u);
}
- boost::uint32_t a[10];
+ boost::random_device::result_type a[10];
rng.generate(a, a + 10);
- return 0;
}
+
+#if !defined(BOOST_WINDOWS)
+BOOST_AUTO_TEST_CASE(random_device_file_not_there)
+{
+ using namespace boost::random;
+ using namespace boost::system;
+
+ BOOST_CHECK_THROW(
+ basic_random_device >("__fictitious_and_nonexistent_filename__"),
+ system_error
+ );
+}
+
+BOOST_AUTO_TEST_CASE(random_device_file)
+{
+ using namespace boost::random;
+ using namespace boost::system;
+
+ const char *tmpfn = "random_device_file_entropy";
+ int wfd = open(tmpfn, O_WRONLY | O_CREAT | O_TRUNC, 0777);
+ BOOST_REQUIRE_NE(wfd, -1);
+
+ basic_random_device > rng(tmpfn);
+
+ // Add some data to the entropy file
+ BOOST_CHECK_EQUAL(2, write(wfd, "AB", 2));
+
+ // We can read two characters before we run out of entropy from the file
+ BOOST_CHECK_EQUAL(0x41, rng());
+ BOOST_CHECK_EQUAL(0x42, rng());
+
+ // Not enough entropy exists for another
+ BOOST_CHECK_THROW(rng(), system_error);
+
+ // clean up
+ BOOST_CHECK_EQUAL(close(wfd), 0);
+ BOOST_CHECK_EQUAL(unlink(tmpfn), 0);
+}
+#endif