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

randombit / botan / 21768358452

06 Feb 2026 10:35PM UTC coverage: 90.064% (-0.003%) from 90.067%
21768358452

Pull #5289

github

web-flow
Merge f589db195 into 8ea0ca252
Pull Request #5289: Further misc header reductions, forward declarations, etc

102238 of 113517 relevant lines covered (90.06%)

11357432.36 hits per line

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

94.44
/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/exceptn.h>
10
#include <botan/internal/cpuid.h>
11
#include <botan/internal/isa_extn.h>
12
#include <botan/internal/loadstor.h>
13
#include <botan/internal/target_info.h>
14

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

19
namespace Botan {
20

21
namespace {
22

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

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

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

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

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

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

70
#elif defined(BOTAN_TARGET_ARCH_IS_PPC_FAMILY)
71

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

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

87
#endif
88

89
   if(success) {
46,134✔
90
      return output;
46,134✔
91
   }
92

93
   return 0;
94
}
95

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

101
      if(success) {
46,134✔
102
         return output;
46,134✔
103
      }
104
   }
105

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

109
}  // namespace
110

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

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

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

136
   while(out.size() >= sizeof(hwrng_output)) {
46,476✔
137
      const hwrng_output r = read_hwrng();
46,021✔
138
      store_le(r, out.data());
46,021✔
139
      out = out.subspan(sizeof(hwrng_output));
46,021✔
140
   }
141

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

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

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

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