comparison DEPENDENCIES/generic/include/boost/uuid/seed_rng.hpp @ 16:2665513ce2d3

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