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

randombit / botan / 19035923289

03 Nov 2025 01:15PM UTC coverage: 90.678% (+0.004%) from 90.674%
19035923289

push

github

web-flow
Merge pull request #5142 from randombit/jack/clang-tidy-asm-simd-warning

Enable the clang-tidy hicpp-no-assembler and portability-simd-intrinsics warnings

100474 of 110803 relevant lines covered (90.68%)

12690096.62 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_ARCH_IS_X86_FAMILY) && !defined(BOTAN_USE_GCC_INLINE_ASM)
14
   #include <immintrin.h>
15
#endif
16

17
namespace Botan {
18

19
namespace {
20

21
#if defined(BOTAN_TARGET_ARCH_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_ARCH_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) {
38,966✔
52
   hwrng_output output = 0;
38,966✔
53
   success = false;
38,966✔
54

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

68
#elif defined(BOTAN_TARGET_ARCH_IS_PPC_FAMILY)
69

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

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

85
#endif
86

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

91
   return 0;
92
}
93

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

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

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

107
}  // namespace
108

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

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

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

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

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

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

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

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

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