prng.ipp 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. //
  2. // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // Official repository: https://github.com/boostorg/beast
  8. //
  9. #ifndef BOOST_BEAST_WEBSOCKET_DETAIL_PRNG_IPP
  10. #define BOOST_BEAST_WEBSOCKET_DETAIL_PRNG_IPP
  11. #include <boost/beast/websocket/detail/prng.hpp>
  12. #include <boost/beast/core/detail/chacha.hpp>
  13. #include <boost/beast/core/detail/pcg.hpp>
  14. #include <atomic>
  15. #include <cstdlib>
  16. #include <mutex>
  17. #include <random>
  18. namespace boost {
  19. namespace beast {
  20. namespace websocket {
  21. namespace detail {
  22. //------------------------------------------------------------------------------
  23. std::uint32_t const*
  24. prng_seed(std::seed_seq* ss)
  25. {
  26. struct data
  27. {
  28. std::uint32_t v[8];
  29. explicit
  30. data(std::seed_seq* pss)
  31. {
  32. if(! pss)
  33. {
  34. std::random_device g;
  35. std::seed_seq ss{
  36. g(), g(), g(), g(),
  37. g(), g(), g(), g()};
  38. ss.generate(v, v+8);
  39. }
  40. else
  41. {
  42. pss->generate(v, v+8);
  43. }
  44. }
  45. };
  46. static data const d(ss);
  47. return d.v;
  48. }
  49. //------------------------------------------------------------------------------
  50. inline
  51. std::uint32_t
  52. make_nonce()
  53. {
  54. static std::atomic<std::uint32_t> nonce{0};
  55. return ++nonce;
  56. }
  57. inline
  58. beast::detail::pcg make_pcg()
  59. {
  60. auto const pv = prng_seed();
  61. return beast::detail::pcg{
  62. ((static_cast<std::uint64_t>(pv[0])<<32)+pv[1]) ^
  63. ((static_cast<std::uint64_t>(pv[2])<<32)+pv[3]) ^
  64. ((static_cast<std::uint64_t>(pv[4])<<32)+pv[5]) ^
  65. ((static_cast<std::uint64_t>(pv[6])<<32)+pv[7]), make_nonce()};
  66. }
  67. #ifdef BOOST_NO_CXX11_THREAD_LOCAL
  68. inline
  69. std::uint32_t
  70. secure_generate()
  71. {
  72. struct generator
  73. {
  74. std::uint32_t operator()()
  75. {
  76. std::lock_guard<std::mutex> guard{mtx};
  77. return gen();
  78. }
  79. beast::detail::chacha<20> gen;
  80. std::mutex mtx;
  81. };
  82. static generator gen{beast::detail::chacha<20>{prng_seed(), make_nonce()}};
  83. return gen();
  84. }
  85. inline
  86. std::uint32_t
  87. fast_generate()
  88. {
  89. struct generator
  90. {
  91. std::uint32_t operator()()
  92. {
  93. std::lock_guard<std::mutex> guard{mtx};
  94. return gen();
  95. }
  96. beast::detail::pcg gen;
  97. std::mutex mtx;
  98. };
  99. static generator gen{make_pcg()};
  100. return gen();
  101. }
  102. #else
  103. inline
  104. std::uint32_t
  105. secure_generate()
  106. {
  107. thread_local static beast::detail::chacha<20> gen{prng_seed(), make_nonce()};
  108. return gen();
  109. }
  110. inline
  111. std::uint32_t
  112. fast_generate()
  113. {
  114. thread_local static beast::detail::pcg gen{make_pcg()};
  115. return gen();
  116. }
  117. #endif
  118. generator
  119. make_prng(bool secure)
  120. {
  121. if (secure)
  122. return &secure_generate;
  123. else
  124. return &fast_generate;
  125. }
  126. } // detail
  127. } // websocket
  128. } // beast
  129. } // boost
  130. #endif