Chris@16: // Boost seed_rng.hpp header file ----------------------------------------------// Chris@16: Chris@16: // Copyright 2007 Andy Tompkins. Chris@16: // Distributed under the Boost Software License, Version 1.0. (See Chris@16: // accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: // Revision History Chris@16: // 09 Nov 2007 - Initial Revision Chris@16: // 25 Feb 2008 - moved to namespace boost::uuids::detail Chris@16: // 28 Nov 2009 - disabled deprecated warnings for MSVC Chris@16: Chris@16: // seed_rng models a UniformRandomNumberGenerator (see Boost.Random). Chris@16: // Random number generators are hard to seed well. This is intended to provide Chris@16: // good seed values for random number generators. Chris@16: // It creates random numbers from a sha1 hash of data from a variary of sources, Chris@16: // all of which are standard function calls. It produces random numbers slowly. Chris@16: // Peter Dimov provided the details of sha1_random_digest_(). Chris@16: // see http://archives.free.net.ph/message/20070507.175609.4c4f503a.en.html Chris@16: Chris@16: #ifndef BOOST_UUID_SEED_RNG_HPP Chris@16: #define BOOST_UUID_SEED_RNG_HPP Chris@16: Chris@16: #include Chris@16: #include // for memcpy Chris@16: #include Chris@16: #include // for time_t, time, clock_t, clock Chris@16: #include // for rand Chris@16: #include // for FILE, fopen, fread, fclose Chris@16: #include Chris@16: //#include //forward declare boost::random::random_device Chris@16: Chris@16: // can't use boost::generator_iterator since boost::random number seed(Iter&, Iter) Chris@16: // functions need a last iterator Chris@16: //#include Chris@16: # include Chris@16: Chris@16: #if defined(_MSC_VER) Chris@16: #pragma warning(push) // Save warning settings. Chris@16: #pragma warning(disable : 4996) // Disable deprecated std::fopen Chris@16: #endif Chris@16: Chris@16: #ifdef BOOST_NO_STDC_NAMESPACE Chris@16: namespace std { Chris@16: using ::memcpy; Chris@16: using ::time_t; Chris@16: using ::time; Chris@16: using ::clock_t; Chris@16: using ::clock; Chris@16: using ::rand; Chris@16: using ::FILE; Chris@16: using ::fopen; Chris@16: using ::fread; Chris@16: using ::fclose; Chris@16: } //namespace std Chris@16: #endif Chris@16: Chris@16: // forward declare random number generators Chris@16: namespace boost { namespace random { Chris@16: class random_device; Chris@16: }} //namespace boost::random Chris@16: Chris@16: namespace boost { Chris@16: namespace uuids { Chris@16: namespace detail { Chris@16: Chris@16: // should this be part of Boost.Random? Chris@16: class seed_rng Chris@16: { Chris@16: public: Chris@16: typedef unsigned int result_type; Chris@16: BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); Chris@16: //BOOST_STATIC_CONSTANT(unsigned int, min_value = 0); Chris@16: //BOOST_STATIC_CONSTANT(unsigned int, max_value = UINT_MAX); Chris@16: Chris@16: public: Chris@16: // note: rd_ intentionally left uninitialized Chris@16: seed_rng() Chris@16: : rd_index_(5) Chris@16: , random_(std::fopen( "/dev/urandom", "rb" )) Chris@16: {} Chris@16: Chris@16: ~seed_rng() Chris@16: { Chris@16: if (random_) { Chris@16: std::fclose(random_); Chris@16: } Chris@16: } Chris@16: Chris@16: result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const Chris@16: { Chris@16: return (std::numeric_limits::min)(); Chris@16: } Chris@16: result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const Chris@16: { Chris@16: return (std::numeric_limits::max)(); Chris@16: } Chris@16: Chris@16: result_type operator()() Chris@16: { Chris@16: if (rd_index_ >= 5) { Chris@16: //get new digest Chris@16: sha1_random_digest_(); Chris@16: Chris@16: rd_index_ = 0; Chris@16: } Chris@16: Chris@16: return rd_[rd_index_++]; Chris@16: } Chris@16: Chris@16: private: Chris@16: inline void ignore_size(size_t) {} Chris@16: Chris@16: static unsigned int * sha1_random_digest_state_() Chris@16: { Chris@16: static unsigned int state[ 5 ]; Chris@16: return state; Chris@16: } Chris@16: Chris@16: void sha1_random_digest_() Chris@16: { Chris@16: boost::uuids::detail::sha1 sha; Chris@16: Chris@16: unsigned int * ps = sha1_random_digest_state_(); Chris@16: Chris@16: unsigned int state[ 5 ]; Chris@16: std::memcpy( state, ps, sizeof( state ) ); // harmless data race Chris@16: Chris@16: sha.process_bytes( (unsigned char const*)state, sizeof( state ) ); Chris@16: sha.process_bytes( (unsigned char const*)&ps, sizeof( ps ) ); Chris@16: Chris@16: { Chris@16: std::time_t tm = std::time( 0 ); Chris@16: sha.process_bytes( (unsigned char const*)&tm, sizeof( tm ) ); Chris@16: } Chris@16: Chris@16: { Chris@16: std::clock_t ck = std::clock(); Chris@16: sha.process_bytes( (unsigned char const*)&ck, sizeof( ck ) ); Chris@16: } Chris@16: Chris@16: { Chris@16: unsigned int rn[] = Chris@16: { static_cast(std::rand()) Chris@16: , static_cast(std::rand()) Chris@16: , static_cast(std::rand()) Chris@16: }; Chris@16: sha.process_bytes( (unsigned char const*)rn, sizeof( rn ) ); Chris@16: } Chris@16: Chris@16: { Chris@16: // intentionally left uninitialized Chris@16: unsigned char buffer[ 20 ]; Chris@16: Chris@16: if(random_) Chris@16: { Chris@16: ignore_size(std::fread( buffer, 1, 20, random_ )); Chris@16: } Chris@16: Chris@16: // using an uninitialized buffer[] if fopen fails Chris@16: // intentional, we rely on its contents being random Chris@16: sha.process_bytes( buffer, sizeof( buffer ) ); Chris@16: } Chris@16: Chris@16: { Chris@16: // *p is intentionally left uninitialized Chris@16: unsigned int * p = new unsigned int; Chris@16: Chris@16: sha.process_bytes( (unsigned char const*)p, sizeof( *p ) ); Chris@16: sha.process_bytes( (unsigned char const*)&p, sizeof( p ) ); Chris@16: Chris@16: delete p; Chris@16: } Chris@16: Chris@16: sha.process_bytes( (unsigned char const*)rd_, sizeof( rd_ ) ); Chris@16: Chris@16: unsigned int digest[ 5 ]; Chris@16: sha.get_digest( digest ); Chris@16: Chris@16: for( int i = 0; i < 5; ++i ) Chris@16: { Chris@16: // harmless data race Chris@16: ps[ i ] ^= digest[ i ]; Chris@16: rd_[ i ] ^= digest[ i ]; Chris@16: } Chris@16: } Chris@16: Chris@16: private: Chris@16: unsigned int rd_[5]; Chris@16: int rd_index_; Chris@16: std::FILE * random_; Chris@16: Chris@16: private: // make seed_rng noncopyable Chris@16: seed_rng(seed_rng const&); Chris@16: seed_rng& operator=(seed_rng const&); Chris@16: }; Chris@16: Chris@16: // almost a copy of boost::generator_iterator Chris@16: // but default constructor sets m_g to NULL Chris@16: template Chris@16: class generator_iterator Chris@16: : public iterator_facade< Chris@16: generator_iterator Chris@16: , typename Generator::result_type Chris@16: , single_pass_traversal_tag Chris@16: , typename Generator::result_type const& Chris@16: > Chris@16: { Chris@16: typedef iterator_facade< Chris@16: generator_iterator Chris@16: , typename Generator::result_type Chris@16: , single_pass_traversal_tag Chris@16: , typename Generator::result_type const& Chris@16: > super_t; Chris@16: Chris@16: public: Chris@16: generator_iterator() : m_g(NULL), m_value(0) {} Chris@16: generator_iterator(Generator* g) : m_g(g), m_value((*m_g)()) {} Chris@16: Chris@16: void increment() Chris@16: { Chris@16: m_value = (*m_g)(); Chris@16: } Chris@16: Chris@16: const typename Generator::result_type& Chris@16: dereference() const Chris@16: { Chris@16: return m_value; Chris@16: } Chris@16: Chris@16: bool equal(generator_iterator const& y) const Chris@16: { Chris@16: return this->m_g == y.m_g && this->m_value == y.m_value; Chris@16: } Chris@16: Chris@16: private: Chris@16: Generator* m_g; Chris@16: typename Generator::result_type m_value; Chris@16: }; Chris@16: Chris@16: // seed() seeds a random number generator with good seed values Chris@16: Chris@16: template Chris@16: inline void seed(UniformRandomNumberGenerator& rng) Chris@16: { Chris@16: seed_rng seed_gen; Chris@16: generator_iterator begin(&seed_gen); Chris@16: generator_iterator end; Chris@16: rng.seed(begin, end); Chris@16: } Chris@16: Chris@16: // random_device does not / can not be seeded Chris@16: template <> Chris@16: inline void seed(boost::random::random_device&) {} Chris@16: Chris@16: // random_device does not / can not be seeded Chris@16: template <> Chris@16: inline void seed(seed_rng&) {} Chris@16: Chris@16: }}} //namespace boost::uuids::detail Chris@16: Chris@16: #if defined(_MSC_VER) Chris@16: #pragma warning(pop) // Restore warnings to previous state. Chris@16: #endif Chris@16: Chris@16: #endif