C++ Distributed Hash Table
rng.h
1 /*
2  * Copyright (C) 2014-2022 Savoir-faire Linux Inc.
3  * Author : Adrien BĂ©raud <adrien.beraud@savoirfairelinux.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <https://www.gnu.org/licenses/>.
17  */
18 
19 #pragma once
20 
21 #include <random>
22 #include <algorithm>
23 #include <functional>
24 #include <thread>
25 #include <stdexcept>
26 
27 namespace dht {
28 namespace crypto {
29 
30 #ifndef _MSC_VER
31 #ifdef _WIN32
32 
37 class random_device {
38 public:
39  using result_type = std::random_device::result_type;
40  using pseudo_engine = std::mt19937_64;
41 
47  static_assert(
48  sizeof(result_type) == 2 ||
49  sizeof(result_type) == 4 ||
50  sizeof(result_type) == 8,
51  "result_type must be 16, 32 or 64 bits");
52 
53  random_device();
54 
55  result_type operator()();
56 
57  static constexpr result_type min() {
58  return std::numeric_limits<result_type>::lowest();
59  }
60 
61  static constexpr result_type max() {
62  return std::numeric_limits<result_type>::max();
63  }
64 
65  double entropy() const {
66  if (hasRdrand() or hasRdseed())
67  return 1.;
68  return 0.;
69  }
70 
71  static bool hasRdrand() {
72  static const bool hasrdrand = _hasRdrand();
73  return hasrdrand;
74  }
75 
76  static bool hasRdseed() {
77  static const bool hasrdseed = _hasRdseed();
78  return hasrdseed;
79  }
80 
81 private:
82  random_device& operator=(random_device&) = delete;
83 
84  pseudo_engine gen;
85  std::uniform_int_distribution<result_type> dis {};
86 
87  static bool hasIntelCpu();
88  static bool _hasRdrand();
89  static bool _hasRdseed();
90 
91  struct CPUIDinfo {
92  unsigned int EAX;
93  unsigned int EBX;
94  unsigned int ECX;
95  unsigned int EDX;
96  CPUIDinfo(const unsigned int func, const unsigned int subfunc);
97  };
98  bool rdrandStep(result_type* r);
99  bool rdrand(result_type* r);
100  bool rdseedStep(result_type* r);
101  bool rdseed(result_type* r);
102 };
103 
104 #else
105 
106 using random_device = std::random_device;
107 
108 #endif
109 #else
110 using random_device = std::random_device;
111 #endif
112 
113 template<class T = std::mt19937, std::size_t N = T::state_size>
114 auto getSeededRandomEngine () -> typename std::enable_if<!!N, T>::type {
115  typename T::result_type random_data[N];
116  for (unsigned i=0; i<256; i++) {
117  try {
118  random_device source;
119  std::generate(std::begin(random_data), std::end(random_data), std::ref(source));
120  std::seed_seq seeds(std::begin(random_data), std::end(random_data));
121  T seededEngine (seeds);
122  return seededEngine;
123  } catch (...) {
124  std::this_thread::sleep_for(std::chrono::milliseconds(1));
125  }
126  }
127  throw std::runtime_error("Can't seed random engine");
128 }
129 
130 }} // dht::crypto
Definition: callbacks.h:35