Qrack  9.0
General classical-emulating-quantum development framework
rdrandwrapper.hpp
Go to the documentation of this file.
1 //
3 // (C) Daniel Strano and the Qrack contributors 2017-2023. All rights reserved.
4 //
5 // This class allows access to on-chip RNG capabilities. The class is adapted from these two sources:
6 // https://codereview.stackexchange.com/questions/147656/checking-if-cpu-supports-rdrand/150230
7 // https://stackoverflow.com/questions/45460146/how-to-use-intels-rdrand-using-inline-assembly-with-net
8 //
9 // Licensed under the GNU Lesser General Public License V3.
10 // See LICENSE.md in the project root or https://www.gnu.org/licenses/lgpl-3.0.en.html
11 // for details.
12 
13 #pragma once
14 
15 #include "qrack_types.hpp"
16 
17 #if ENABLE_DEVRAND
18 #include <sys/random.h>
19 #endif
20 
21 #if ENABLE_RDRAND
22 #if _MSC_VER
23 #include <intrin.h>
24 #else
25 #include <cpuid.h>
26 #endif
27 #include <immintrin.h>
28 #endif
29 
30 namespace Qrack {
31 
32 #if ENABLE_RNDFILE && !ENABLE_DEVRAND
33 // See https://stackoverflow.com/questions/1008019/c-singleton-design-pattern
34 class RandFile {
35 public:
36  static RandFile& getInstance()
37  {
38  static RandFile instance;
39  return instance;
40  }
41 
42  unsigned NextRaw()
43  {
44  size_t fSize = 0;
45  unsigned v;
46  while (fSize < 1) {
47  fSize = fread(&v, sizeof(unsigned), 1, dataFile);
48  if (fSize < 1) {
49  _readNextRandDataFile();
50  }
51  }
52 
53  return v;
54  }
55 
56 private:
57  RandFile() { _readNextRandDataFile(); }
58  ~RandFile()
59  {
60  if (dataFile) {
61  fclose(dataFile);
62  }
63  }
64 
65  size_t fileOffset;
66  FILE* dataFile;
67  void _readNextRandDataFile();
68 
69 public:
70  RandFile(RandFile const&) = delete;
71  void operator=(RandFile const&) = delete;
72 };
73 #endif
74 
75 class RdRandom {
76 private:
77  bool getRdRand(unsigned* pv)
78  {
79 #if ENABLE_RDRAND || ENABLE_DEVRAND
80  constexpr int max_rdrand_tries = 10;
81  for (int i = 0; i < max_rdrand_tries; ++i) {
82 #if ENABLE_DEVRAND
83  if (sizeof(unsigned) == getrandom(reinterpret_cast<char*>(pv), sizeof(unsigned), 0))
84 #else
85  if (_rdrand32_step(pv))
86 #endif
87  return true;
88  }
89 #endif
90  return false;
91  }
92 
93 public:
95  {
96 #if ENABLE_RDRAND
97  const unsigned flag_RDRAND = (1 << 30);
98 
99 #if _MSC_VER
100  int ex[4];
101  __cpuid(ex, 1);
102 
103  return ((ex[2] & flag_RDRAND) == flag_RDRAND);
104 #else
105  unsigned eax, ebx, ecx, edx;
106  ecx = 0;
107  __get_cpuid(1, &eax, &ebx, &ecx, &edx);
108 
109  return ((ecx & flag_RDRAND) == flag_RDRAND);
110 #endif
111 
112 #else
113  return false;
114 #endif
115  }
116 
117 #if ENABLE_RNDFILE && !ENABLE_DEVRAND
118  unsigned NextRaw() { return RandFile::getInstance().NextRaw(); }
119 #else
120  unsigned NextRaw()
121  {
122  unsigned v;
123  if (!getRdRand(&v)) {
124  throw std::runtime_error("Random number generator failed up to retry limit.");
125  }
126 
127  return v;
128  }
129 #endif
130 
132  {
133  unsigned v = NextRaw();
134 
135  real1_f res = ZERO_R1_F;
136  real1_f part = ONE_R1_F;
137  for (unsigned i = 0U; i < 32U; ++i) {
138  part /= 2;
139  if ((v >> i) & 1U) {
140  res += part;
141  }
142  }
143 
144 #if FPPOW > 5
145  v = NextRaw();
146 
147  for (unsigned i = 0U; i < 32U; ++i) {
148  part /= 2;
149  if ((v >> i) & 1U) {
150  res += part;
151  }
152  }
153 #endif
154 
155  return res;
156  }
157 };
158 } // namespace Qrack
Definition: rdrandwrapper.hpp:75
bool getRdRand(unsigned *pv)
Definition: rdrandwrapper.hpp:77
unsigned NextRaw()
Definition: rdrandwrapper.hpp:120
real1_f Next()
Definition: rdrandwrapper.hpp:131
bool SupportsRDRAND()
Definition: rdrandwrapper.hpp:94
Definition: complex16x2simd.hpp:25
constexpr real1_f ZERO_R1_F
Definition: qrack_types.hpp:152
constexpr real1_f ONE_R1_F
Definition: qrack_types.hpp:154
float real1_f
Definition: qrack_types.hpp:64
MICROSOFT_QUANTUM_DECL void U(_In_ uintq sid, _In_ uintq q, _In_ double theta, _In_ double phi, _In_ double lambda)
(External API) 3-parameter unitary gate
Definition: pinvoke_api.cpp:1362