Fabcoin Core  0.16.2
P2P Digital Currency
rdrand.cpp
Go to the documentation of this file.
1 // rdrand.cpp - written and placed in public domain by Jeffrey Walton and Uri Blumenthal.
2 // Copyright assigned to Crypto++ project.
3 
4 #include "pch.h"
5 #include "config.h"
6 #include "cryptlib.h"
7 #include "secblock.h"
8 #include "rdrand.h"
9 #include "cpu.h"
10 
11 #if CRYPTOPP_MSC_VERSION
12 # pragma warning(disable: 4100)
13 #endif
14 
15 // This file (and friends) provides both RDRAND and RDSEED, but its somewhat
16 // experimental. They were added at Crypto++ 5.6.3. At compile time, it
17 // indirectly uses CRYPTOPP_BOOL_{X86|X32|X64} (via CRYPTOPP_CPUID_AVAILABLE)
18 // to select an implementation or "throw NotImplemented". At runtime, the
19 // class uses the result of CPUID to determine if RDRAND or RDSEED are
20 // available. If not available, a lazy throw strategy is used. I.e., the
21 // throw is deferred until GenerateBlock() is called.
22 
23 // Here's the naming convention for the functions....
24 // MSC = Microsoft Compiler (and compatibles)
25 // GCC = GNU Compiler (and compatibles)
26 // ALL = MSC and GCC (and compatibles)
27 // RRA = RDRAND, Assembly
28 // RSA = RDSEED, Assembly
29 // RRI = RDRAND, Intrinsic
30 // RSA = RDSEED, Intrinsic
31 
34 
35 // For Linux, install NASM, run rdrand-nasm.asm, add the apppropriate
36 // object file to the Makefile's LIBOBJS (rdrand-x{86|32|64}.o). After
37 // that, define these. They are not enabled by default because they
38 // are not easy to cut-in in the Makefile.
39 
40 #if 0
41 #define NASM_RDRAND_ASM_AVAILABLE 1
42 #define NASM_RDSEED_ASM_AVAILABLE 1
43 #endif
44 
47 
48 // In general, the library's ASM code is best on Windows, and Intrinsics is
49 // the best code under GCC. Clang is missing symbols, so it gets ASM.
50 // The NASM code is optimized well on Linux, but its not easy to cut-in.
51 #if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
52 # ifndef CRYPTOPP_CPUID_AVAILABLE
53 # define CRYPTOPP_CPUID_AVAILABLE
54 # endif
55 #endif
56 
57 #if defined(CRYPTOPP_CPUID_AVAILABLE)
58 # if defined(CRYPTOPP_MSC_VERSION)
59 # define MASM_RDRAND_ASM_AVAILABLE 1
60 # define MASM_RDSEED_ASM_AVAILABLE 1
61 # elif defined(CRYPTOPP_LLVM_CLANG_VERSION) || defined(CRYPTOPP_APPLE_CLANG_VERSION)
62 # define GCC_RDRAND_ASM_AVAILABLE 1
63 # define GCC_RDSEED_ASM_AVAILABLE 1
64 # elif defined(__SUNPRO_CC)
65 # if defined(__RDRND__) && (__SUNPRO_CC >= 0x5130)
66 # define ALL_RDRAND_INTRIN_AVAILABLE 1
67 # elif (__SUNPRO_CC >= 0x5100)
68 # define GCC_RDRAND_ASM_AVAILABLE 1
69 # endif
70 # if defined(__RDSEED__) && (__SUNPRO_CC >= 0x5140)
71 # define ALL_RDSEED_INTRIN_AVAILABLE 1
72 # elif (__SUNPRO_CC >= 0x5100)
73 # define GCC_RDSEED_ASM_AVAILABLE 1
74 # endif
75 # elif defined(CRYPTOPP_GCC_VERSION)
76 # if defined(__RDRND__) && (CRYPTOPP_GCC_VERSION >= 30200)
77 # define ALL_RDRAND_INTRIN_AVAILABLE 1
78 # else
79 # define GCC_RDRAND_ASM_AVAILABLE 1
80 # endif
81 # if defined(__RDSEED__) && (CRYPTOPP_GCC_VERSION >= 30200)
82 # define ALL_RDSEED_INTRIN_AVAILABLE 1
83 # else
84 # define GCC_RDSEED_ASM_AVAILABLE 1
85 # endif
86 # endif
87 #endif
88 
89 // Debug diagnostics
90 #if 0
91 # if MASM_RDRAND_ASM_AVAILABLE
92 # pragma message ("MASM_RDRAND_ASM_AVAILABLE is 1")
93 # elif NASM_RDRAND_ASM_AVAILABLE
94 # pragma message ("NASM_RDRAND_ASM_AVAILABLE is 1")
95 # elif GCC_RDRAND_ASM_AVAILABLE
96 # pragma message ("GCC_RDRAND_ASM_AVAILABLE is 1")
97 # elif ALL_RDRAND_INTRIN_AVAILABLE
98 # pragma message ("ALL_RDRAND_INTRIN_AVAILABLE is 1")
99 # else
100 # pragma message ("RDRAND is not available")
101 # endif
102 # if MASM_RDSEED_ASM_AVAILABLE
103 # pragma message ("MASM_RDSEED_ASM_AVAILABLE is 1")
104 # elif NASM_RDSEED_ASM_AVAILABLE
105 # pragma message ("NASM_RDSEED_ASM_AVAILABLE is 1")
106 # elif GCC_RDSEED_ASM_AVAILABLE
107 # pragma message ("GCC_RDSEED_ASM_AVAILABLE is 1")
108 # elif ALL_RDSEED_INTRIN_AVAILABLE
109 # pragma message ("ALL_RDSEED_INTRIN_AVAILABLE is 1")
110 # else
111 # pragma message ("RDSEED is not available")
112 # endif
113 #endif
114 
117 
118 #if (ALL_RDRAND_INTRIN_AVAILABLE || ALL_RDSEED_INTRIN_AVAILABLE)
119 # include <immintrin.h> // rdrand, MSC, ICC, GCC, and SunCC
120 # if defined(__GNUC__) && (CRYPTOPP_GCC_VERSION >= 40600)
121 # include <x86intrin.h> // rdseed for some compilers, like GCC
122 # endif
123 # if defined(__has_include)
124 # if __has_include(<x86intrin.h>)
125 # include <x86intrin.h> // rdrand for Clang (immintrin.h); rdseed for Clang (rdseedintrin.h)
126 # endif
127 # endif
128 #endif
129 
130 #if MASM_RDRAND_ASM_AVAILABLE
131 # ifdef _M_X64
132 extern "C" int CRYPTOPP_FASTCALL MASM_RRA_GenerateBlock(byte*, size_t, unsigned int);
133 // # pragma comment(lib, "rdrand-x64.lib")
134 # else
135 extern "C" int MASM_RRA_GenerateBlock(byte*, size_t, unsigned int);
136 // # pragma comment(lib, "rdrand-x86.lib")
137 # endif
138 #endif
139 
140 #if MASM_RDSEED_ASM_AVAILABLE
141 # ifdef _M_X64
142 extern "C" int CRYPTOPP_FASTCALL MASM_RSA_GenerateBlock(byte*, size_t, unsigned int);
143 // # pragma comment(lib, "rdrand-x64.lib")
144 # else
145 extern "C" int MASM_RSA_GenerateBlock(byte*, size_t, unsigned int);
146 // # pragma comment(lib, "rdrand-x86.lib")
147 # endif
148 #endif
149 
150 #if NASM_RDRAND_ASM_AVAILABLE
151 extern "C" int NASM_RRA_GenerateBlock(byte*, size_t, unsigned int);
152 #endif
153 
154 #if NASM_RDSEED_ASM_AVAILABLE
155 extern "C" int NASM_RSA_GenerateBlock(byte*, size_t, unsigned int);
156 #endif
157 
160 
162 
163 #if ALL_RDRAND_INTRIN_AVAILABLE
164 static int ALL_RRI_GenerateBlock(byte *output, size_t size, unsigned int safety)
165 {
166  CRYPTOPP_ASSERT((output && size) || !(output || size));
167 #if CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32
168  word32 val;
169 #else
170  word64 val;
171 #endif
172 
173  while (size >= sizeof(val))
174  {
175 #if CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32
176  if (_rdrand32_step((word32*)output))
177 #else
178  // Cast due to GCC, http://github.com/weidai11/cryptopp/issues/236
179  if (_rdrand64_step(reinterpret_cast<unsigned long long*>(output)))
180 #endif
181  {
182  output += sizeof(val);
183  size -= sizeof(val);
184  }
185  else
186  {
187  if (!safety--)
188  {
189  CRYPTOPP_ASSERT(0);
190  return 0;
191  }
192  }
193  }
194 
195  if (size)
196  {
197 #if CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32
198  if (_rdrand32_step(&val))
199 #else
200  // Cast due to GCC, http://github.com/weidai11/cryptopp/issues/236
201  if (_rdrand64_step(reinterpret_cast<unsigned long long*>(&val)))
202 #endif
203  {
204  memcpy(output, &val, size);
205  size = 0;
206  }
207  else
208  {
209  if (!safety--)
210  {
211  CRYPTOPP_ASSERT(0);
212  return 0;
213  }
214  }
215  }
216 
217  SecureWipeBuffer(&val, 1);
218 
219  return int(size == 0);
220 }
221 #endif // ALL_RDRAND_INTRINSIC_AVAILABLE
222 
223 #if GCC_RDRAND_ASM_AVAILABLE
224 static int GCC_RRA_GenerateBlock(byte *output, size_t size, unsigned int safety)
225 {
226  CRYPTOPP_ASSERT((output && size) || !(output || size));
227 #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
228  word64 val;
229 #else
230  word32 val;
231 #endif
232  char rc;
233  while (size)
234  {
235  __asm__ volatile(
236 #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
237  ".byte 0x48, 0x0f, 0xc7, 0xf0;\n" // rdrand rax
238 #else
239  ".byte 0x0f, 0xc7, 0xf0;\n" // rdrand eax
240 #endif
241  "setc %1; "
242  : "=a" (val), "=qm" (rc)
243  :
244  : "cc"
245  );
246 
247  if (rc)
248  {
249  if (size >= sizeof(val))
250  {
251  PutWord(true, LITTLE_ENDIAN_ORDER, output, val, NULL);
252  output += sizeof(val);
253  size -= sizeof(val);
254  }
255  else
256  {
257  memcpy(output, &val, size);
258  size = 0;
259  }
260  }
261  else
262  {
263  if (!safety--)
264  {
265  CRYPTOPP_ASSERT(0);
266  return 0;
267  }
268  }
269  }
270 
271  SecureWipeBuffer(&val, 1);
272 
273  return int(size == 0);
274 }
275 
276 #endif // GCC_RDRAND_ASM_AVAILABLE
277 
278 #if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
279 void RDRAND::GenerateBlock(byte *output, size_t size)
280 {
281  CRYPTOPP_UNUSED(output), CRYPTOPP_UNUSED(size);
282  CRYPTOPP_ASSERT((output && size) || !(output || size));
283 
284  if(!HasRDRAND())
285  throw NotImplemented("RDRAND: rdrand is not available on this platform");
286 
287  int rc; CRYPTOPP_UNUSED(rc);
288 #if MASM_RDRAND_ASM_AVAILABLE
289  rc = MASM_RRA_GenerateBlock(output, size, m_retries);
290  if (!rc) { throw RDRAND_Err("MASM_RRA_GenerateBlock"); }
291 #elif NASM_RDRAND_ASM_AVAILABLE
292  rc = NASM_RRA_GenerateBlock(output, size, m_retries);
293  if (!rc) { throw RDRAND_Err("NASM_RRA_GenerateBlock"); }
294 #elif ALL_RDRAND_INTRIN_AVAILABLE
295  rc = ALL_RRI_GenerateBlock(output, size, m_retries);
296  if (!rc) { throw RDRAND_Err("ALL_RRI_GenerateBlock"); }
297 #elif GCC_RDRAND_ASM_AVAILABLE
298  rc = GCC_RRA_GenerateBlock(output, size, m_retries);
299  if (!rc) { throw RDRAND_Err("GCC_RRA_GenerateBlock"); }
300 #else
301  // RDRAND not detected at compile time, and no suitable compiler found
302  throw NotImplemented("RDRAND: failed to find a suitable implementation???");
303 #endif // CRYPTOPP_CPUID_AVAILABLE
304 }
305 
306 void RDRAND::DiscardBytes(size_t n)
307 {
308  // RoundUpToMultipleOf is used because a full word is read, and its cheaper
309  // to discard full words. There's no sense in dealing with tail bytes.
310  CRYPTOPP_ASSERT(HasRDRAND());
311 #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
313  n = RoundUpToMultipleOf(n, sizeof(word64));
314 #else
316  n = RoundUpToMultipleOf(n, sizeof(word32));
317 #endif
318 
319  size_t count = STDMIN(n, discard.SizeInBytes());
320  while (count)
321  {
322  GenerateBlock(discard.BytePtr(), count);
323  n -= count;
324  count = STDMIN(n, discard.SizeInBytes());
325  }
326 }
327 #endif // CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64
328 
331 
332 #if ALL_RDSEED_INTRIN_AVAILABLE
333 static int ALL_RSI_GenerateBlock(byte *output, size_t size, unsigned int safety)
334 {
335  CRYPTOPP_ASSERT((output && size) || !(output || size));
336 #if CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32
337  word32 val;
338 #else
339  word64 val;
340 #endif
341 
342  while (size >= sizeof(val))
343  {
344 #if CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32
345  if (_rdseed32_step((word32*)output))
346 #else
347  // Cast due to GCC, http://github.com/weidai11/cryptopp/issues/236
348  if (_rdseed64_step(reinterpret_cast<unsigned long long*>(output)))
349 #endif
350  {
351  output += sizeof(val);
352  size -= sizeof(val);
353  }
354  else
355  {
356  if (!safety--)
357  {
358  CRYPTOPP_ASSERT(0);
359  return 0;
360  }
361  }
362  }
363 
364  if (size)
365  {
366 #if CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32
367  if (_rdseed32_step(&val))
368 #else
369  // Cast due to GCC, http://github.com/weidai11/cryptopp/issues/236
370  if (_rdseed64_step(reinterpret_cast<unsigned long long*>(&val)))
371 #endif
372  {
373  memcpy(output, &val, size);
374  size = 0;
375  }
376  else
377  {
378  if (!safety--)
379  {
380  CRYPTOPP_ASSERT(0);
381  return 0;
382  }
383  }
384  }
385 
386  SecureWipeBuffer(&val, 1);
387 
388  return int(size == 0);
389 }
390 #endif // ALL_RDSEED_INTRIN_AVAILABLE
391 
392 #if GCC_RDSEED_ASM_AVAILABLE
393 static int GCC_RSA_GenerateBlock(byte *output, size_t size, unsigned int safety)
394 {
395  CRYPTOPP_ASSERT((output && size) || !(output || size));
396 #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
397  word64 val;
398 #else
399  word32 val;
400 #endif
401  char rc;
402  while (size)
403  {
404  __asm__ volatile(
405 #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
406  ".byte 0x48, 0x0f, 0xc7, 0xf8;\n" // rdseed rax
407 #else
408  ".byte 0x0f, 0xc7, 0xf8;\n" // rdseed eax
409 #endif
410  "setc %1; "
411  : "=a" (val), "=qm" (rc)
412  :
413  : "cc"
414  );
415 
416  if (rc)
417  {
418  if (size >= sizeof(val))
419  {
420  PutWord(true, LITTLE_ENDIAN_ORDER, output, val, NULL);
421  output += sizeof(val);
422  size -= sizeof(val);
423  }
424  else
425  {
426  memcpy(output, &val, size);
427  size = 0;
428  }
429  }
430  else
431  {
432  if (!safety--)
433  {
434  CRYPTOPP_ASSERT(0);
435  return 0;
436  }
437  }
438  }
439 
440  SecureWipeBuffer(&val, 1);
441 
442  return int(size == 0);
443 }
444 #endif // GCC_RDSEED_ASM_AVAILABLE
445 
446 #if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
447 void RDSEED::GenerateBlock(byte *output, size_t size)
448 {
449  CRYPTOPP_UNUSED(output), CRYPTOPP_UNUSED(size);
450  CRYPTOPP_ASSERT((output && size) || !(output || size));
451 
452  if(!HasRDSEED())
453  throw NotImplemented("RDSEED: rdseed is not available on this platform");
454 
455  int rc; CRYPTOPP_UNUSED(rc);
456 #if MASM_RDSEED_ASM_AVAILABLE
457  rc = MASM_RSA_GenerateBlock(output, size, m_retries);
458  if (!rc) { throw RDSEED_Err("MASM_RSA_GenerateBlock"); }
459 #elif NASM_RDSEED_ASM_AVAILABLE
460  rc = NASM_RSA_GenerateBlock(output, size, m_retries);
461  if (!rc) { throw RDRAND_Err("NASM_RSA_GenerateBlock"); }
462 #elif ALL_RDSEED_INTRIN_AVAILABLE
463  rc = ALL_RSI_GenerateBlock(output, size, m_retries);
464  if (!rc) { throw RDSEED_Err("ALL_RSI_GenerateBlock"); }
465 #elif GCC_RDSEED_ASM_AVAILABLE
466  rc = GCC_RSA_GenerateBlock(output, size, m_retries);
467  if (!rc) { throw RDSEED_Err("GCC_RSA_GenerateBlock"); }
468 #else
469  // RDSEED not detected at compile time, and no suitable compiler found
470  throw NotImplemented("RDSEED: failed to find a suitable implementation???");
471 #endif
472 }
473 
474 void RDSEED::DiscardBytes(size_t n)
475 {
476  // RoundUpToMultipleOf is used because a full word is read, and its cheaper
477  // to discard full words. There's no sense in dealing with tail bytes.
478  CRYPTOPP_ASSERT(HasRDSEED());
479 #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
481  n = RoundUpToMultipleOf(n, sizeof(word64));
482 #else
484  n = RoundUpToMultipleOf(n, sizeof(word32));
485 #endif
486 
487  size_t count = STDMIN(n, discard.SizeInBytes());
488  while (count)
489  {
490  GenerateBlock(discard.BytePtr(), count);
491  n -= count;
492  count = STDMIN(n, discard.SizeInBytes());
493  }
494 }
495 #endif // CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64
496 
void SecureWipeBuffer(T *buf, size_t n)
Sets each element of an array to 0.
Definition: misc.h:1085
virtual void GenerateBlock(byte *output, size_t size)
Generate random array of bytes.
Definition: rdrand.h:162
uint8_t byte
Definition: Common.h:57
virtual void GenerateBlock(byte *output, size_t size)
Generate random array of bytes.
Definition: rdrand.h:78
void PutWord(bool assumeAligned, ByteOrder order, byte *block, T value, const byte *xorBlock=NULL)
Access a block of memory.
Definition: misc.h:2123
#define NAMESPACE_BEGIN(x)
Definition: config.h:200
size_t count
Definition: ExecStats.cpp:37
Abstract base classes that provide a uniform interface to this library.
Library configuration file.
Classes for RDRAND and RDSEED.
byte order is little-endian
Definition: cryptlib.h:126
Classes and functions for secure memory allocations.
Exception thrown when a RDRAND generator encounters a generator related error.
Definition: rdrand.h:29
virtual void DiscardBytes(size_t n)
Generate and discard n bytes.
Definition: rdrand.h:176
A method was called which was not implemented.
Definition: cryptlib.h:205
virtual void DiscardBytes(size_t n)
Generate and discard n bytes.
Definition: rdrand.h:92
unsigned long long word64
Definition: config.h:240
Fixed size stack-based SecBlock.
Definition: secblock.h:753
const T & STDMIN(const T &a, const T &b)
Replacement function for std::min.
Definition: misc.h:477
#define CRYPTOPP_ASSERT(exp)
Definition: trap.h:92
Functions for CPU features and intrinsics.
uint8_t const size_t const size
Definition: sha3.h:20
void * memcpy(void *a, const void *b, size_t c)
#define CRYPTOPP_UNUSED(x)
Definition: config.h:741
#define CRYPTOPP_FASTCALL
Definition: config.h:363
T1 RoundUpToMultipleOf(const T1 &n, const T2 &m)
Rounds a value up to a multiple of a second value.
Definition: misc.h:905
unsigned int m_retries
Definition: rdrand.h:110
#define NAMESPACE_END
Definition: config.h:201
size_type SizeInBytes() const
Provides the number of bytes in the SecBlock.
Definition: secblock.h:538
unsigned int word32
Definition: config.h:231
Exception thrown when a RDSEED generator encounters a generator related error.
Definition: rdrand.h:116
byte * BytePtr()
Provides a byte pointer to the first element in the memory block.
Definition: secblock.h:531