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

randombit / botan / 20899440751

11 Jan 2026 05:56PM UTC coverage: 90.434% (+0.004%) from 90.43%
20899440751

push

github

web-flow
Merge pull request #5229 from randombit/jack/cpu-rng-isa

Add a BOTAN_FN_ISA flag for CPU RNG function

101806 of 112575 relevant lines covered (90.43%)

12789603.4 hits per line

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

94.74
/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/isa_extn.h>
11
#include <botan/internal/loadstor.h>
12
#include <botan/internal/target_info.h>
13

14
#if defined(BOTAN_TARGET_ARCH_IS_X86_FAMILY) && !defined(BOTAN_USE_GCC_INLINE_ASM)
15
   #include <immintrin.h>
16
#endif
17

18
namespace Botan {
19

20
namespace {
21

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

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

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

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

52
hwrng_output BOTAN_FN_ISA_RNG read_hwrng(bool& success) {
38,966✔
53
   hwrng_output output = 0;  // NOLINT(*-const-correctness) clang-tidy doesn't understand inline asm
38,966✔
54
   success = false;
38,966✔
55

56
#if defined(BOTAN_TARGET_ARCH_IS_X86_FAMILY)
57
   int cf = 0;  // NOLINT(*-const-correctness) clang-tidy doesn't understand inline asm
38,966✔
58
   #if defined(BOTAN_USE_GCC_INLINE_ASM)
59
   // same asm seq works for 32 and 64 bit
60
   // NOLINTNEXTLINE(*-no-assembler)
61
   asm volatile("rdrand %0; adcl $0,%1" : "=r"(output), "=r"(cf) : "0"(output), "1"(cf) : "cc");
38,966✔
62
   #elif defined(BOTAN_TARGET_ARCH_IS_X86_32)
63
   cf = _rdrand32_step(&output);
64
   #else
65
   cf = _rdrand64_step(reinterpret_cast<unsigned long long*>(&output));
66
   #endif
67
   success = (1 == cf);
38,966✔
68

69
#elif defined(BOTAN_TARGET_ARCH_IS_PPC_FAMILY)
70

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

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

86
#endif
87

88
   if(success) {
38,966✔
89
      return output;
38,966✔
90
   }
91

92
   return 0;
93
}
94

95
hwrng_output read_hwrng() {
38,966✔
96
   for(size_t i = 0; i < HWRNG_RETRIES; ++i) {
38,966✔
97
      bool success = false;
38,966✔
98
      const hwrng_output output = read_hwrng(success);
38,966✔
99

100
      if(success) {
38,966✔
101
         return output;
38,966✔
102
      }
103
   }
104

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

108
}  // namespace
109

110
//static
111
bool Processor_RNG::available() {
14✔
112
#if defined(BOTAN_TARGET_ARCH_IS_X86_FAMILY)
113
   return CPUID::has(CPUID::Feature::RDRAND);
14✔
114
#elif defined(BOTAN_TARGET_ARCH_IS_PPC_FAMILY)
115
   return CPUID::has(CPUID::Feature::DARN);
116
#else
117
   return false;
118
#endif
119
}
120

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

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

135
   while(out.size() >= sizeof(hwrng_output)) {
39,245✔
136
      const hwrng_output r = read_hwrng();
38,853✔
137
      store_le(r, out.data());
38,853✔
138
      out = out.subspan(sizeof(hwrng_output));
38,853✔
139
   }
140

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

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

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

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

166
}  // 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