• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 13210394651

08 Feb 2025 12:33AM UTC coverage: 91.656% (-0.006%) from 91.662%
13210394651

push

github

web-flow
Merge pull request #4642 from randombit/jack/target-info-header

Add internal target_info.h header

94837 of 103471 relevant lines covered (91.66%)

11243945.63 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.11
/src/lib/rng/processor_rng/processor_rng.cpp
1
/*
2
* (C) 2016,2019,2020 Jack Lloyd
3
*
4
* Botan is released under the Simplified BSD License (see license.txt)
5
*/
6

7
#include <botan/processor_rng.h>
8

9
#include <botan/internal/cpuid.h>
10
#include <botan/internal/loadstor.h>
11
#include <botan/internal/target_info.h>
12

13
#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
14
   #include <immintrin.h>
15
#endif
16

17
namespace Botan {
18

19
namespace {
20

21
#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
22
/*
23
   * According to Intel, RDRAND is guaranteed to generate a random
24
   * number within 10 retries on a working CPU
25
   */
26
const size_t HWRNG_RETRIES = 10;
27

28
#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
29
/**
30
    * PowerISA 3.0 p.78:
31
    *    When the error value is obtained, software is expected to repeat the
32
    *    operation. [...] The recommended number of attempts may be
33
    *    implementation specific. In the absence of other guidance, ten attempts
34
    *    should be adequate.
35
    */
36
const size_t HWRNG_RETRIES = 10;
37

38
#else
39
/*
40
   * Lacking specific guidance we give the CPU quite a bit of leeway
41
   */
42
const size_t HWRNG_RETRIES = 512;
43
#endif
44

45
#if defined(BOTAN_TARGET_ARCH_IS_X86_32)
46
typedef uint32_t hwrng_output;
47
#else
48
typedef uint64_t hwrng_output;
49
#endif
50

51
hwrng_output read_hwrng(bool& success) {
47,158✔
52
   hwrng_output output = 0;
47,158✔
53
   success = false;
47,158✔
54

55
#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
56
   int cf = 0;
47,158✔
57
   #if defined(BOTAN_USE_GCC_INLINE_ASM)
58
   // same asm seq works for 32 and 64 bit
59
   asm volatile("rdrand %0; adcl $0,%1" : "=r"(output), "=r"(cf) : "0"(output), "1"(cf) : "cc");
94,316✔
60
   #elif defined(BOTAN_TARGET_ARCH_IS_X86_32)
61
   cf = _rdrand32_step(&output);
62
   #else
63
   cf = _rdrand64_step(reinterpret_cast<unsigned long long*>(&output));
64
   #endif
65
   success = (1 == cf);
47,158✔
66

67
#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
68

69
   /*
70
   DARN indicates error by returning 0xFF..FF, ie is biased. Which is crazy.
71
   Avoid the bias by invoking it twice and, assuming both succeed, returning the
72
   XOR of the two results, which should unbias the output.
73
   */
74
   uint64_t output2 = 0;
75
   // DARN codes are 0: 32-bit conditioned, 1: 64-bit conditioned, 2: 64-bit raw (ala RDSEED)
76
   asm volatile("darn %0, 1" : "=r"(output));
77
   asm volatile("darn %0, 1" : "=r"(output2));
78

79
   if((~output) != 0 && (~output2) != 0) {
80
      output ^= output2;
81
      success = true;
82
   }
83

84
#endif
85

86
   if(success) {
47,158✔
87
      return output;
47,158✔
88
   }
89

90
   return 0;
91
}
92

93
hwrng_output read_hwrng() {
47,158✔
94
   for(size_t i = 0; i < HWRNG_RETRIES; ++i) {
47,158✔
95
      bool success = false;
47,158✔
96
      hwrng_output output = read_hwrng(success);
47,158✔
97

98
      if(success) {
×
99
         return output;
47,158✔
100
      }
101
   }
102

103
   throw PRNG_Unseeded("Processor RNG instruction failed to produce output within expected iterations");
×
104
}
105

106
}  // namespace
107

108
//static
109
bool Processor_RNG::available() {
14✔
110
#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
111
   return CPUID::has_rdrand();
14✔
112
#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
113
   return CPUID::has_darn_rng();
114
#else
115
   return false;
116
#endif
117
}
118

119
std::string Processor_RNG::name() const {
15✔
120
#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
121
   return "rdrand";
15✔
122
#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
123
   return "darn";
124
#else
125
   return "hwrng";
126
#endif
127
}
128

129
void Processor_RNG::fill_bytes_with_input(std::span<uint8_t> out, std::span<const uint8_t> in) {
456✔
130
   // No way to provide entropy to processor-specific generator, ignore...
131
   BOTAN_UNUSED(in);
456✔
132

133
   while(out.size() >= sizeof(hwrng_output)) {
47,501✔
134
      const hwrng_output r = read_hwrng();
47,045✔
135
      store_le(r, out.data());
47,045✔
136
      out = out.subspan(sizeof(hwrng_output));
47,045✔
137
   }
138

139
   if(!out.empty()) {
456✔
140
      // at most sizeof(hwrng_output)-1 bytes left
141
      const hwrng_output r = read_hwrng();
113✔
142
      uint8_t hwrng_bytes[sizeof(hwrng_output)];
113✔
143
      store_le(r, hwrng_bytes);
113✔
144

145
      for(size_t i = 0; i != out.size(); ++i) {
563✔
146
         out[i] = hwrng_bytes[i];
450✔
147
      }
148
   }
149
}
456✔
150

151
Processor_RNG::Processor_RNG() {
7✔
152
   if(!Processor_RNG::available()) {
7✔
153
      throw Invalid_State("Current CPU does not support RNG instruction");
×
154
   }
155
}
7✔
156

157
size_t Processor_RNG::reseed(Entropy_Sources& /*srcs*/,
1✔
158
                             size_t /*poll_bits*/,
159
                             std::chrono::milliseconds /*poll_timeout*/) {
160
   /* no way to add entropy */
161
   return 0;
1✔
162
}
163

164
}  // namespace Botan
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc