prng.ipp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  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 <boost/align/aligned_alloc.hpp>
  15. #include <boost/throw_exception.hpp>
  16. #include <atomic>
  17. #include <cstdlib>
  18. #include <mutex>
  19. #include <new>
  20. #include <random>
  21. #include <stdexcept>
  22. namespace boost {
  23. namespace beast {
  24. namespace websocket {
  25. namespace detail {
  26. //------------------------------------------------------------------------------
  27. std::uint32_t const*
  28. prng_seed(std::seed_seq* ss)
  29. {
  30. struct data
  31. {
  32. std::uint32_t v[8];
  33. explicit
  34. data(std::seed_seq* pss)
  35. {
  36. if(! pss)
  37. {
  38. std::random_device g;
  39. std::seed_seq ss{
  40. g(), g(), g(), g(),
  41. g(), g(), g(), g()};
  42. ss.generate(v, v+8);
  43. }
  44. else
  45. {
  46. pss->generate(v, v+8);
  47. }
  48. }
  49. };
  50. static data const d(ss);
  51. return d.v;
  52. }
  53. //------------------------------------------------------------------------------
  54. template<class T>
  55. class prng_pool
  56. {
  57. std::mutex m_;
  58. T* head_ = nullptr;
  59. public:
  60. static
  61. prng_pool&
  62. instance()
  63. {
  64. static prng_pool p;
  65. return p;
  66. }
  67. ~prng_pool()
  68. {
  69. for(auto p = head_; p;)
  70. {
  71. auto next = p->next;
  72. p->~T();
  73. boost::alignment::aligned_free(p);
  74. p = next;
  75. }
  76. }
  77. prng::ref
  78. acquire()
  79. {
  80. {
  81. std::lock_guard<
  82. std::mutex> g(m_);
  83. if(head_)
  84. {
  85. auto p = head_;
  86. head_ = head_->next;
  87. return prng::ref(*p);
  88. }
  89. }
  90. auto p = boost::alignment::aligned_alloc(
  91. 16, sizeof(T));
  92. if(! p)
  93. BOOST_THROW_EXCEPTION(std::bad_alloc{});
  94. return prng::ref(*(::new(p) T()));
  95. }
  96. void
  97. release(T& t)
  98. {
  99. std::lock_guard<
  100. std::mutex> g(m_);
  101. t.next = head_;
  102. head_ = &t;
  103. }
  104. };
  105. prng::ref
  106. make_prng_no_tls(bool secure)
  107. {
  108. class fast_prng final : public prng
  109. {
  110. int refs_ = 0;
  111. beast::detail::pcg r_;
  112. public:
  113. fast_prng* next = nullptr;
  114. fast_prng()
  115. : r_(
  116. []{
  117. auto const pv = prng_seed();
  118. return
  119. ((static_cast<std::uint64_t>(pv[0])<<32)+pv[1]) ^
  120. ((static_cast<std::uint64_t>(pv[2])<<32)+pv[3]) ^
  121. ((static_cast<std::uint64_t>(pv[4])<<32)+pv[5]) ^
  122. ((static_cast<std::uint64_t>(pv[6])<<32)+pv[7]);
  123. }(),
  124. []{
  125. static std::atomic<
  126. std::uint32_t> nonce{0};
  127. return ++nonce;
  128. }())
  129. {
  130. }
  131. protected:
  132. prng&
  133. acquire() noexcept override
  134. {
  135. ++refs_;
  136. return *this;
  137. }
  138. void
  139. release() noexcept override
  140. {
  141. if(--refs_ == 0)
  142. prng_pool<fast_prng>::instance().release(*this);
  143. }
  144. value_type
  145. operator()() noexcept override
  146. {
  147. return r_();
  148. }
  149. };
  150. class secure_prng final : public prng
  151. {
  152. int refs_ = 0;
  153. beast::detail::chacha<20> r_;
  154. public:
  155. secure_prng* next = nullptr;
  156. secure_prng()
  157. : r_(prng_seed(), []
  158. {
  159. static std::atomic<
  160. std::uint64_t> nonce{0};
  161. return ++nonce;
  162. }())
  163. {
  164. }
  165. protected:
  166. prng&
  167. acquire() noexcept override
  168. {
  169. ++refs_;
  170. return *this;
  171. }
  172. void
  173. release() noexcept override
  174. {
  175. if(--refs_ == 0)
  176. prng_pool<secure_prng>::instance().release(*this);
  177. }
  178. value_type
  179. operator()() noexcept override
  180. {
  181. return r_();
  182. }
  183. };
  184. if(secure)
  185. return prng_pool<secure_prng>::instance().acquire();
  186. return prng_pool<fast_prng>::instance().acquire();
  187. }
  188. //------------------------------------------------------------------------------
  189. #ifndef BOOST_NO_CXX11_THREAD_LOCAL
  190. prng::ref
  191. make_prng_tls(bool secure)
  192. {
  193. class fast_prng final : public prng
  194. {
  195. beast::detail::pcg r_;
  196. public:
  197. fast_prng()
  198. : r_(
  199. []{
  200. auto const pv = prng_seed();
  201. return
  202. ((static_cast<std::uint64_t>(pv[0])<<32)+pv[1]) ^
  203. ((static_cast<std::uint64_t>(pv[2])<<32)+pv[3]) ^
  204. ((static_cast<std::uint64_t>(pv[4])<<32)+pv[5]) ^
  205. ((static_cast<std::uint64_t>(pv[6])<<32)+pv[7]);
  206. }(),
  207. []{
  208. static std::atomic<
  209. std::uint32_t> nonce{0};
  210. return ++nonce;
  211. }())
  212. {
  213. }
  214. protected:
  215. prng&
  216. acquire() noexcept override
  217. {
  218. return *this;
  219. }
  220. void
  221. release() noexcept override
  222. {
  223. }
  224. value_type
  225. operator()() noexcept override
  226. {
  227. return r_();
  228. }
  229. };
  230. class secure_prng final : public prng
  231. {
  232. beast::detail::chacha<20> r_;
  233. public:
  234. secure_prng()
  235. : r_(prng_seed(), []
  236. {
  237. static std::atomic<
  238. std::uint64_t> nonce{0};
  239. return ++nonce;
  240. }())
  241. {
  242. }
  243. protected:
  244. prng&
  245. acquire() noexcept override
  246. {
  247. return *this;
  248. }
  249. void
  250. release() noexcept override
  251. {
  252. }
  253. value_type
  254. operator()() noexcept override
  255. {
  256. return r_();
  257. }
  258. };
  259. if(secure)
  260. {
  261. thread_local secure_prng sp;
  262. return prng::ref(sp);
  263. }
  264. thread_local fast_prng fp;
  265. return prng::ref(fp);
  266. }
  267. #endif
  268. //------------------------------------------------------------------------------
  269. prng::ref
  270. make_prng(bool secure)
  271. {
  272. #ifdef BOOST_NO_CXX11_THREAD_LOCAL
  273. return make_prng_no_tls(secure);
  274. #else
  275. return make_prng_tls(secure);
  276. #endif
  277. }
  278. } // detail
  279. } // websocket
  280. } // beast
  281. } // boost
  282. #endif