Chris@16
|
1 // Boost seed_rng.hpp header file ----------------------------------------------//
|
Chris@16
|
2
|
Chris@16
|
3 // Copyright 2007 Andy Tompkins.
|
Chris@16
|
4 // Distributed under the Boost Software License, Version 1.0. (See
|
Chris@16
|
5 // accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
6 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
7
|
Chris@16
|
8 // Revision History
|
Chris@16
|
9 // 09 Nov 2007 - Initial Revision
|
Chris@16
|
10 // 25 Feb 2008 - moved to namespace boost::uuids::detail
|
Chris@16
|
11 // 28 Nov 2009 - disabled deprecated warnings for MSVC
|
Chris@16
|
12
|
Chris@16
|
13 // seed_rng models a UniformRandomNumberGenerator (see Boost.Random).
|
Chris@16
|
14 // Random number generators are hard to seed well. This is intended to provide
|
Chris@16
|
15 // good seed values for random number generators.
|
Chris@16
|
16 // It creates random numbers from a sha1 hash of data from a variary of sources,
|
Chris@16
|
17 // all of which are standard function calls. It produces random numbers slowly.
|
Chris@16
|
18 // Peter Dimov provided the details of sha1_random_digest_().
|
Chris@16
|
19 // see http://archives.free.net.ph/message/20070507.175609.4c4f503a.en.html
|
Chris@16
|
20
|
Chris@16
|
21 #ifndef BOOST_UUID_SEED_RNG_HPP
|
Chris@16
|
22 #define BOOST_UUID_SEED_RNG_HPP
|
Chris@16
|
23
|
Chris@16
|
24 #include <boost/config.hpp>
|
Chris@16
|
25 #include <cstring> // for memcpy
|
Chris@16
|
26 #include <limits>
|
Chris@16
|
27 #include <ctime> // for time_t, time, clock_t, clock
|
Chris@16
|
28 #include <cstdlib> // for rand
|
Chris@16
|
29 #include <cstdio> // for FILE, fopen, fread, fclose
|
Chris@16
|
30 #include <boost/uuid/sha1.hpp>
|
Chris@16
|
31 //#include <boost/nondet_random.hpp> //forward declare boost::random::random_device
|
Chris@16
|
32
|
Chris@16
|
33 // can't use boost::generator_iterator since boost::random number seed(Iter&, Iter)
|
Chris@16
|
34 // functions need a last iterator
|
Chris@16
|
35 //#include <boost/generator_iterator.hpp>
|
Chris@16
|
36 # include <boost/iterator/iterator_facade.hpp>
|
Chris@16
|
37
|
Chris@16
|
38 #if defined(_MSC_VER)
|
Chris@16
|
39 #pragma warning(push) // Save warning settings.
|
Chris@16
|
40 #pragma warning(disable : 4996) // Disable deprecated std::fopen
|
Chris@16
|
41 #endif
|
Chris@16
|
42
|
Chris@16
|
43 #ifdef BOOST_NO_STDC_NAMESPACE
|
Chris@16
|
44 namespace std {
|
Chris@16
|
45 using ::memcpy;
|
Chris@16
|
46 using ::time_t;
|
Chris@16
|
47 using ::time;
|
Chris@16
|
48 using ::clock_t;
|
Chris@16
|
49 using ::clock;
|
Chris@16
|
50 using ::rand;
|
Chris@16
|
51 using ::FILE;
|
Chris@16
|
52 using ::fopen;
|
Chris@16
|
53 using ::fread;
|
Chris@16
|
54 using ::fclose;
|
Chris@16
|
55 } //namespace std
|
Chris@16
|
56 #endif
|
Chris@16
|
57
|
Chris@16
|
58 // forward declare random number generators
|
Chris@16
|
59 namespace boost { namespace random {
|
Chris@16
|
60 class random_device;
|
Chris@16
|
61 }} //namespace boost::random
|
Chris@16
|
62
|
Chris@16
|
63 namespace boost {
|
Chris@16
|
64 namespace uuids {
|
Chris@16
|
65 namespace detail {
|
Chris@16
|
66
|
Chris@16
|
67 // should this be part of Boost.Random?
|
Chris@16
|
68 class seed_rng
|
Chris@16
|
69 {
|
Chris@16
|
70 public:
|
Chris@16
|
71 typedef unsigned int result_type;
|
Chris@16
|
72 BOOST_STATIC_CONSTANT(bool, has_fixed_range = false);
|
Chris@16
|
73 //BOOST_STATIC_CONSTANT(unsigned int, min_value = 0);
|
Chris@16
|
74 //BOOST_STATIC_CONSTANT(unsigned int, max_value = UINT_MAX);
|
Chris@16
|
75
|
Chris@16
|
76 public:
|
Chris@16
|
77 // note: rd_ intentionally left uninitialized
|
Chris@16
|
78 seed_rng()
|
Chris@16
|
79 : rd_index_(5)
|
Chris@16
|
80 , random_(std::fopen( "/dev/urandom", "rb" ))
|
Chris@16
|
81 {}
|
Chris@16
|
82
|
Chris@16
|
83 ~seed_rng()
|
Chris@16
|
84 {
|
Chris@16
|
85 if (random_) {
|
Chris@16
|
86 std::fclose(random_);
|
Chris@16
|
87 }
|
Chris@16
|
88 }
|
Chris@16
|
89
|
Chris@16
|
90 result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const
|
Chris@16
|
91 {
|
Chris@16
|
92 return (std::numeric_limits<result_type>::min)();
|
Chris@16
|
93 }
|
Chris@16
|
94 result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const
|
Chris@16
|
95 {
|
Chris@16
|
96 return (std::numeric_limits<result_type>::max)();
|
Chris@16
|
97 }
|
Chris@16
|
98
|
Chris@16
|
99 result_type operator()()
|
Chris@16
|
100 {
|
Chris@16
|
101 if (rd_index_ >= 5) {
|
Chris@16
|
102 //get new digest
|
Chris@16
|
103 sha1_random_digest_();
|
Chris@16
|
104
|
Chris@16
|
105 rd_index_ = 0;
|
Chris@16
|
106 }
|
Chris@16
|
107
|
Chris@16
|
108 return rd_[rd_index_++];
|
Chris@16
|
109 }
|
Chris@16
|
110
|
Chris@16
|
111 private:
|
Chris@16
|
112 inline void ignore_size(size_t) {}
|
Chris@16
|
113
|
Chris@16
|
114 static unsigned int * sha1_random_digest_state_()
|
Chris@16
|
115 {
|
Chris@16
|
116 static unsigned int state[ 5 ];
|
Chris@16
|
117 return state;
|
Chris@16
|
118 }
|
Chris@16
|
119
|
Chris@16
|
120 void sha1_random_digest_()
|
Chris@16
|
121 {
|
Chris@16
|
122 boost::uuids::detail::sha1 sha;
|
Chris@16
|
123
|
Chris@16
|
124 unsigned int * ps = sha1_random_digest_state_();
|
Chris@16
|
125
|
Chris@16
|
126 unsigned int state[ 5 ];
|
Chris@16
|
127 std::memcpy( state, ps, sizeof( state ) ); // harmless data race
|
Chris@16
|
128
|
Chris@16
|
129 sha.process_bytes( (unsigned char const*)state, sizeof( state ) );
|
Chris@16
|
130 sha.process_bytes( (unsigned char const*)&ps, sizeof( ps ) );
|
Chris@16
|
131
|
Chris@16
|
132 {
|
Chris@16
|
133 std::time_t tm = std::time( 0 );
|
Chris@16
|
134 sha.process_bytes( (unsigned char const*)&tm, sizeof( tm ) );
|
Chris@16
|
135 }
|
Chris@16
|
136
|
Chris@16
|
137 {
|
Chris@16
|
138 std::clock_t ck = std::clock();
|
Chris@16
|
139 sha.process_bytes( (unsigned char const*)&ck, sizeof( ck ) );
|
Chris@16
|
140 }
|
Chris@16
|
141
|
Chris@16
|
142 {
|
Chris@16
|
143 unsigned int rn[] =
|
Chris@16
|
144 { static_cast<unsigned int>(std::rand())
|
Chris@16
|
145 , static_cast<unsigned int>(std::rand())
|
Chris@16
|
146 , static_cast<unsigned int>(std::rand())
|
Chris@16
|
147 };
|
Chris@16
|
148 sha.process_bytes( (unsigned char const*)rn, sizeof( rn ) );
|
Chris@16
|
149 }
|
Chris@16
|
150
|
Chris@16
|
151 {
|
Chris@16
|
152 // intentionally left uninitialized
|
Chris@16
|
153 unsigned char buffer[ 20 ];
|
Chris@16
|
154
|
Chris@16
|
155 if(random_)
|
Chris@16
|
156 {
|
Chris@16
|
157 ignore_size(std::fread( buffer, 1, 20, random_ ));
|
Chris@16
|
158 }
|
Chris@16
|
159
|
Chris@16
|
160 // using an uninitialized buffer[] if fopen fails
|
Chris@16
|
161 // intentional, we rely on its contents being random
|
Chris@16
|
162 sha.process_bytes( buffer, sizeof( buffer ) );
|
Chris@16
|
163 }
|
Chris@16
|
164
|
Chris@16
|
165 {
|
Chris@16
|
166 // *p is intentionally left uninitialized
|
Chris@16
|
167 unsigned int * p = new unsigned int;
|
Chris@16
|
168
|
Chris@16
|
169 sha.process_bytes( (unsigned char const*)p, sizeof( *p ) );
|
Chris@16
|
170 sha.process_bytes( (unsigned char const*)&p, sizeof( p ) );
|
Chris@16
|
171
|
Chris@16
|
172 delete p;
|
Chris@16
|
173 }
|
Chris@16
|
174
|
Chris@16
|
175 sha.process_bytes( (unsigned char const*)rd_, sizeof( rd_ ) );
|
Chris@16
|
176
|
Chris@16
|
177 unsigned int digest[ 5 ];
|
Chris@16
|
178 sha.get_digest( digest );
|
Chris@16
|
179
|
Chris@16
|
180 for( int i = 0; i < 5; ++i )
|
Chris@16
|
181 {
|
Chris@16
|
182 // harmless data race
|
Chris@16
|
183 ps[ i ] ^= digest[ i ];
|
Chris@16
|
184 rd_[ i ] ^= digest[ i ];
|
Chris@16
|
185 }
|
Chris@16
|
186 }
|
Chris@16
|
187
|
Chris@16
|
188 private:
|
Chris@16
|
189 unsigned int rd_[5];
|
Chris@16
|
190 int rd_index_;
|
Chris@16
|
191 std::FILE * random_;
|
Chris@16
|
192
|
Chris@16
|
193 private: // make seed_rng noncopyable
|
Chris@16
|
194 seed_rng(seed_rng const&);
|
Chris@16
|
195 seed_rng& operator=(seed_rng const&);
|
Chris@16
|
196 };
|
Chris@16
|
197
|
Chris@16
|
198 // almost a copy of boost::generator_iterator
|
Chris@16
|
199 // but default constructor sets m_g to NULL
|
Chris@16
|
200 template <class Generator>
|
Chris@16
|
201 class generator_iterator
|
Chris@16
|
202 : public iterator_facade<
|
Chris@16
|
203 generator_iterator<Generator>
|
Chris@16
|
204 , typename Generator::result_type
|
Chris@16
|
205 , single_pass_traversal_tag
|
Chris@16
|
206 , typename Generator::result_type const&
|
Chris@16
|
207 >
|
Chris@16
|
208 {
|
Chris@16
|
209 typedef iterator_facade<
|
Chris@16
|
210 generator_iterator<Generator>
|
Chris@16
|
211 , typename Generator::result_type
|
Chris@16
|
212 , single_pass_traversal_tag
|
Chris@16
|
213 , typename Generator::result_type const&
|
Chris@16
|
214 > super_t;
|
Chris@16
|
215
|
Chris@16
|
216 public:
|
Chris@16
|
217 generator_iterator() : m_g(NULL), m_value(0) {}
|
Chris@16
|
218 generator_iterator(Generator* g) : m_g(g), m_value((*m_g)()) {}
|
Chris@16
|
219
|
Chris@16
|
220 void increment()
|
Chris@16
|
221 {
|
Chris@16
|
222 m_value = (*m_g)();
|
Chris@16
|
223 }
|
Chris@16
|
224
|
Chris@16
|
225 const typename Generator::result_type&
|
Chris@16
|
226 dereference() const
|
Chris@16
|
227 {
|
Chris@16
|
228 return m_value;
|
Chris@16
|
229 }
|
Chris@16
|
230
|
Chris@16
|
231 bool equal(generator_iterator const& y) const
|
Chris@16
|
232 {
|
Chris@16
|
233 return this->m_g == y.m_g && this->m_value == y.m_value;
|
Chris@16
|
234 }
|
Chris@16
|
235
|
Chris@16
|
236 private:
|
Chris@16
|
237 Generator* m_g;
|
Chris@16
|
238 typename Generator::result_type m_value;
|
Chris@16
|
239 };
|
Chris@16
|
240
|
Chris@16
|
241 // seed() seeds a random number generator with good seed values
|
Chris@16
|
242
|
Chris@16
|
243 template <typename UniformRandomNumberGenerator>
|
Chris@16
|
244 inline void seed(UniformRandomNumberGenerator& rng)
|
Chris@16
|
245 {
|
Chris@16
|
246 seed_rng seed_gen;
|
Chris@16
|
247 generator_iterator<seed_rng> begin(&seed_gen);
|
Chris@16
|
248 generator_iterator<seed_rng> end;
|
Chris@16
|
249 rng.seed(begin, end);
|
Chris@16
|
250 }
|
Chris@16
|
251
|
Chris@16
|
252 // random_device does not / can not be seeded
|
Chris@16
|
253 template <>
|
Chris@16
|
254 inline void seed<boost::random::random_device>(boost::random::random_device&) {}
|
Chris@16
|
255
|
Chris@16
|
256 // random_device does not / can not be seeded
|
Chris@16
|
257 template <>
|
Chris@16
|
258 inline void seed<seed_rng>(seed_rng&) {}
|
Chris@16
|
259
|
Chris@16
|
260 }}} //namespace boost::uuids::detail
|
Chris@16
|
261
|
Chris@16
|
262 #if defined(_MSC_VER)
|
Chris@16
|
263 #pragma warning(pop) // Restore warnings to previous state.
|
Chris@16
|
264 #endif
|
Chris@16
|
265
|
Chris@16
|
266 #endif
|