seed_rng.hpp 7.1 KB

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