Skip to content

Commit 4875f16

Browse files
committed
Update the random_device implementation so that it:
* Supports more platforms optimally, for example CloudABI, OpenBSD, and Windows UWP * Is easier to maintain as each platform's implementation is in a separate file * Removes the library dependency on Boost.System * Is header-only, and thus makes Boost.Random header-only * Is well-tested for happy and sad paths Removes the token-based random_device explicit constructor. Adds a new exception "entropy_error" to handle errors getting entropy. Removed the detail auto_link implementation inside Boost.Random as it is no longer necessary - the one in Boost.Config is sufficient. Also added a top-level Jamfile that builds the example subdirectory with each build, as one of the examples needed to be updated in order to build. This will prevent rot in the example directory. Note: Other libraries that link against Boost.Random (like Boost.Uuid) will fail to build until they stop trying to link against Boost.Random. This fixes boostorg#20 This fixes boostorg#22
1 parent e4b0b2f commit 4875f16

26 files changed

Lines changed: 1358 additions & 427 deletions

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
/doc/html
22
/doc/reference.xml
3-
/test/rng.saved
3+
/example/rng.saved
4+
**/rng.saved

Jamfile

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Boost.Random Library Jamfile
2+
#
3+
# Copyright (c) 2017 James E. King, III
4+
#
5+
# Use, modification, and distribution are subject to the
6+
# Boost Software License, Version 1.0. (See accompanying file
7+
# LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8+
9+
project libs/random
10+
: requirements
11+
12+
<warnings>all
13+
14+
<toolset>clang:<cxxflags>-Wextra
15+
<toolset>clang:<cxxflags>-ansi
16+
# <toolset>clang:<cxxflags>-pedantic
17+
<toolset>clang:<cxxflags>-Wno-c++11-long-long
18+
19+
<toolset>gcc:<cxxflags>-Wextra
20+
<toolset>gcc:<cxxflags>-ansi
21+
# <toolset>gcc:<cxxflags>-pedantic
22+
<toolset>gcc:<cxxflags>-Wno-long-long
23+
;
24+
25+
# pedantic mode disabled due to issue in multiprecision
26+
# https://github.com/boostorg/multiprecision/issues/34
27+
28+
# please order by name to ease maintenance
29+
build-project example ;
30+
build-project test ;

build/Jamfile.v2

Lines changed: 0 additions & 18 deletions
This file was deleted.

doc/nondet_random.qbk

Lines changed: 70 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,14 @@
2222
{
2323
public:
2424
typedef unsigned int result_type;
25-
static const bool has_fixed_range = true;
26-
static const result_type min_value = /* implementation defined */;
27-
static const result_type max_value = /* implementation defined */;
28-
result_type min() const;
29-
result_type max() const;
30-
explicit random_device(const std::string& token = default_token);
31-
~random_device();
25+
static const bool has_fixed_range = false;
26+
static result_type min();
27+
static result_type max();
3228
double entropy() const;
3329
unsigned int operator()();
30+
void randomize(void *, size_t siz);
31+
const char * name() const;
32+
template<class Iter> void generate(Iter first, Iter last);
3433
};
3534

3635
[endsect]
@@ -54,15 +53,24 @@ provide a special device for exactly this purpose. It seems to be impossible
5453
to emulate the functionality using Standard C++ only, so users should be aware
5554
that this class may not be available on all platforms.]
5655

56+
The optimal operating system specific implementation for entropy generation
57+
is selected automatically at compile time. See notes below for more details.
58+
5759
[endsect]
5860

5961
[section Members]
6062

61-
explicit random_device(const std::string& token = default_token)
63+
static result_type min()
64+
65+
Returns: the smallest value that the random_device can produce.
66+
67+
Throws: Nothing.
6268

63-
Effects: Constructs a random_device, optionally using the given token as an
64-
access specification (for example, a URL) to some implementation-defined
65-
service for monitoring a stochastic process.
69+
static result_type max()
70+
71+
Returns: the largest value that the random_device can produce.
72+
73+
Throws: Nothing.
6674

6775
double entropy() const
6876

@@ -72,32 +80,64 @@ generator (e.g. a pseudo-random number engine) has entropy 0.
7280

7381
Throws: Nothing.
7482

83+
unsigned int operator()()
84+
85+
Returns: a random value in the range [min(), max()]
86+
87+
Throws: entropy_error, if an error occurs obtaining entropy from the operating system
88+
89+
void randomize(void *ptr, size_t siz)
90+
91+
Fills a buffer with random bytes.
92+
93+
Throws: entropy_error, if an error occurs obtaining entropy from the operating system
94+
95+
const char * name() const
96+
97+
Returns: the name of the entropy provider
98+
99+
Throws: Nothing.
100+
101+
template<class Iter> void generate(Iter first, Iter last)
102+
103+
Allows random_device to be used as a SeedSeq for
104+
PseudoRandomNumberGeneration seeding.
105+
106+
Throws: entropy_error, if an error occurs obtaining entropy from the operating system
107+
108+
[endsect]
109+
110+
[section Entropy Providers]
111+
112+
The selection logic for the entropy provider is as follows:
113+
114+
1. On CloudABI, or on OpenBSD version 2.1 or later, `arc4random` will be used.
115+
2. On Windows platforms, the `bcrypt` provider is used unless targeting Windows CE or Windows XP, where the `wincrypt` provider is used.
116+
3. On Linux platforms with glibc >= 2.25, `getentropy` is used, otherwise it is treated as a POSIX platform.
117+
4. On POSIX platforms, entropy is obtained by reading from `/dev/urandom`.
118+
75119
[endsect]
76120

77-
Implementation Note for Linux
78-
On the Linux operating system, token is interpreted as a filesystem path. It
79-
is assumed that this path denotes an operating system pseudo-device which
80-
generates a stream of non-deterministic random numbers. The pseudo-device
81-
should never signal an error or end-of-file. Otherwise, std::ios_base::failure
82-
is thrown. By default, random_device uses the /dev/urandom pseudo-device to
83-
retrieve the random numbers. Another option would be to specify the
84-
/dev/random pseudo-device, which blocks on reads if the entropy pool has no
85-
more random bits available.
121+
[section Preprocessor Definitions]
122+
123+
`BOOST_RANDOM_NO_LIB` (Windows) - disable auto-linking for the `bcrypt` and `wincrypt` provider when building with MSVC
124+
`BOOST_RANDOM_PROVIDER_SHOW` - display the chosen entropy provider at compile time
86125

87126
[endsect]
88127

89-
[section Performance]
128+
[section Notes]
90129

91-
The test program nondet_random_speed.cpp measures the execution times of the
92-
nondet_random.hpp implementation of the above algorithms in a tight loop.
93-
The performance has been evaluated on a Pentium Pro 200 MHz with gcc 2.95.2,
94-
Linux 2.2.13, glibc 2.1.2.
130+
To fill a buffer with random bytes, call random_device::randomize. Keep in mind
131+
that there may be operating-system specific setup and teardown costs associated
132+
with entropy generation, therefore if you are going to call this often, you will
133+
want to reuse the random_device.
95134

96-
[table preformance
97-
[[class] [time per invocation \[usec\]]]
98-
[[random_device] [92.0]]
99-
]
135+
It is easy to use `random_device` as a seed sequence for a PseudoRandomNumberGenerator:
136+
137+
boost::mt19937 twister;
138+
boost::random_device rng;
139+
twister.seed(rng);
100140

101-
The measurement error is estimated at +/- 1 usec.
141+
[endsect]
102142

103143
[endsect]

example/Jamfile.v2

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,21 @@
77
# accompanying file LICENSE_1_0.txt or copy at
88
# http://www.boost.org/LICENSE_1_0.txt)
99

10+
project libs/random/example
11+
: requirements
12+
13+
# boost.jam defines BOOST_ALL_NO_LIB for builds
14+
# which cannot be undefined?
15+
<toolset>msvc:<define>BOOST_RANDOM_FORCE_AUTO_LINK
16+
<toolset>gcc-mingw:<linkflags>"-lbcrypt"
17+
18+
# boost::random needs this setting for a warning free build:
19+
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
20+
21+
# link static for easier debugging - uncomment if you need to debug...
22+
# <link>static
23+
;
24+
1025
run die.cpp ;
1126
run weighted_die.cpp ;
12-
run password.cpp /boost//random ;
27+
run password.cpp ;

example/password.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
password.
1717
*/
1818

19-
2019
#include <boost/random/random_device.hpp>
2120
#include <boost/random/uniform_int_distribution.hpp>
21+
#include <iostream>
2222

2323
int main() {
2424
/*<< We first define the characters that we're going

include/boost/random/detail/auto_link.hpp

Lines changed: 0 additions & 40 deletions
This file was deleted.

include/boost/random/detail/generator_seed_seq.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* boost random/mersenne_twister.hpp header file
1+
/* boost random/detail/generator_seed_seq.hpp header file
22
*
33
* Copyright Jens Maurer 2000-2001
44
* Copyright Steven Watanabe 2010
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
//
2+
// Copyright (c) 2017 James E. King III
3+
//
4+
// Distributed under the Boost Software License, Version 1.0.
5+
// (See accompanying file LICENSE_1_0.txt or copy at
6+
// http://www.boost.org/LICENCE_1_0.txt)
7+
//
8+
// Platform-specific random entropy provider
9+
//
10+
11+
#ifndef BOOST_RANDOM_DETAIL_RANDOM_PROVIDER_HPP
12+
#define BOOST_RANDOM_DETAIL_RANDOM_PROVIDER_HPP
13+
14+
#include <boost/core/noncopyable.hpp>
15+
#include <boost/cstdint.hpp>
16+
#include <boost/limits.hpp>
17+
#include <boost/static_assert.hpp>
18+
#include <boost/type_traits/is_integral.hpp>
19+
#include <boost/type_traits/is_unsigned.hpp>
20+
#include <boost/random/entropy_error.hpp>
21+
#include <iterator>
22+
23+
// Detection of the platform is separated from inclusion of the correct
24+
// header to facilitate mock testing of the provider implementations.
25+
26+
#include <boost/random/detail/random_provider_detect_platform.hpp>
27+
#include <boost/random/detail/random_provider_include_platform.hpp>
28+
29+
30+
namespace boost {
31+
namespace random {
32+
namespace detail {
33+
34+
//! \brief Contains code common to all random_provider implementations.
35+
//! \note random_provider_base is required to provide this method:
36+
//! void get_random_bytes(void *buf, size_t siz);
37+
//! \note noncopyable because of some base implementations so
38+
//! this makes it uniform across platforms to avoid any
39+
//! porting surprises
40+
class random_provider
41+
: public detail::random_provider_base,
42+
public noncopyable
43+
{
44+
public:
45+
//! Leverage the provider as a SeedSeq for
46+
//! PseudoRandomNumberGeneration seeding
47+
//! \note: See Boost.Random documentation for more details
48+
template<class Iter>
49+
void generate(Iter first, Iter last)
50+
{
51+
typedef typename std::iterator_traits<Iter>::value_type value_type;
52+
BOOST_STATIC_ASSERT(is_integral<value_type>::value);
53+
BOOST_STATIC_ASSERT(is_unsigned<value_type>::value);
54+
BOOST_STATIC_ASSERT(sizeof(value_type) * CHAR_BIT >= 32);
55+
56+
for (; first != last; ++first)
57+
{
58+
get_random_bytes(&*first, sizeof(*first));
59+
*first &= (std::numeric_limits<boost::uint32_t>::max)();
60+
}
61+
}
62+
63+
//! Return the name of the selected provider
64+
const char * name() const
65+
{
66+
return BOOST_RANDOM_PROVIDER_STRINGIFY(BOOST_RANDOM_PROVIDER_NAME);
67+
}
68+
};
69+
70+
} // detail
71+
} // random
72+
} // boost
73+
74+
#endif // BOOST_RANDOM_DETAIL_RANDOM_PROVIDER_HPP
75+
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//
2+
// Copyright (c) 2017 James E. King III
3+
//
4+
// Distributed under the Boost Software License, Version 1.0.
5+
// (See accompanying file LICENSE_1_0.txt or copy at
6+
// http://www.boost.org/LICENCE_1_0.txt)
7+
//
8+
// "A Replacement Call for Random"
9+
// https://man.openbsd.org/arc4random.3
10+
//
11+
12+
#include <stdlib.h>
13+
14+
namespace boost {
15+
namespace random {
16+
namespace detail {
17+
18+
class random_provider_base
19+
{
20+
public:
21+
//! Obtain entropy and place it into a memory location
22+
//! \param[in] buf the location to write entropy
23+
//! \param[in] siz the number of bytes to acquire
24+
void get_random_bytes(void *buf, size_t siz)
25+
{
26+
arc4random_buf(buf, siz);
27+
}
28+
};
29+
30+
} // detail
31+
} // random
32+
} // boost

0 commit comments

Comments
 (0)