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

randombit / botan / 20899605032

11 Jan 2026 06:09PM UTC coverage: 90.433% (-0.001%) from 90.434%
20899605032

Pull #5228

github

web-flow
Merge c7b68522d into b941fcb56
Pull Request #5228: processor_rng: Add support for ARMv8.5-A FEAT_RNG extension

101805 of 112575 relevant lines covered (90.43%)

12906044.11 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
#elif defined(BOTAN_TARGET_ARCH_IS_ARM64) && !defined(BOTAN_USE_GCC_INLINE_ASM)
17
   #include <arm_acle.h>
18
#endif
19

20
namespace Botan {
21

22
namespace {
23

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

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

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

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

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

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

71
#elif defined(BOTAN_TARGET_ARCH_IS_PPC_FAMILY)
72

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

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

88
#elif defined(BOTAN_TARGET_ARCH_IS_ARM64)
89

90
   uint64_t nzcv = 0;  // NOLINT(*-const-correctness) clang-tidy doesn't understand inline asm
91
   #if defined(BOTAN_USE_GCC_INLINE_ASM)
92
   // NOLINTNEXTLINE(*-no-assembler)
93
   asm volatile("mrs %0, rndr; mrs %1, nzcv" : "=r"(output), "=r"(nzcv) : "0"(output), "1"(nzcv) : "cc");
94
   #else
95
   nzcv = __rndr(&output);
96
   #endif
97
   success = (0 == nzcv);
98

99
#endif
100

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

105
   return 0;
106
}
107

108
hwrng_output read_hwrng() {
38,966✔
109
   for(size_t i = 0; i < HWRNG_RETRIES; ++i) {
38,966✔
110
      bool success = false;
38,966✔
111
      const hwrng_output output = read_hwrng(success);
38,966✔
112

113
      if(success) {
38,966✔
114
         return output;
38,966✔
115
      }
116
   }
117

118
   throw PRNG_Unseeded("Processor RNG instruction failed to produce output within expected iterations");
×
119
}
120

121
}  // namespace
122

123
//static
124
bool Processor_RNG::available() {
14✔
125
#if defined(BOTAN_TARGET_ARCH_IS_X86_FAMILY)
126
   return CPUID::has(CPUID::Feature::RDRAND);
14✔
127
#elif defined(BOTAN_TARGET_ARCH_IS_PPC_FAMILY)
128
   return CPUID::has(CPUID::Feature::DARN);
129
#elif defined(BOTAN_TARGET_ARCH_IS_ARM64)
130
   return CPUID::has(CPUID::Feature::RNG);
131
#else
132
   return false;
133
#endif
134
}
135

136
std::string Processor_RNG::name() const {
15✔
137
#if defined(BOTAN_TARGET_ARCH_IS_X86_FAMILY)
138
   return "rdrand";
15✔
139
#elif defined(BOTAN_TARGET_ARCH_IS_PPC_FAMILY)
140
   return "darn";
141
#elif defined(BOTAN_TARGET_ARCH_IS_ARM64)
142
   return "rng";
143
#else
144
   return "hwrng";
145
#endif
146
}
147

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

152
   while(out.size() >= sizeof(hwrng_output)) {
39,245✔
153
      const hwrng_output r = read_hwrng();
38,853✔
154
      store_le(r, out.data());
38,853✔
155
      out = out.subspan(sizeof(hwrng_output));
38,853✔
156
   }
157

158
   if(!out.empty()) {
392✔
159
      // at most sizeof(hwrng_output)-1 bytes left
160
      const hwrng_output r = read_hwrng();
113✔
161
      uint8_t hwrng_bytes[sizeof(hwrng_output)];
113✔
162
      store_le(r, hwrng_bytes);
113✔
163

164
      for(size_t i = 0; i != out.size(); ++i) {
563✔
165
         out[i] = hwrng_bytes[i];
450✔
166
      }
167
   }
168
}
392✔
169

170
Processor_RNG::Processor_RNG() {
7✔
171
   if(!Processor_RNG::available()) {
7✔
172
      throw Invalid_State("Current CPU does not support RNG instruction");
×
173
   }
174
}
7✔
175

176
size_t Processor_RNG::reseed(Entropy_Sources& /*srcs*/,
1✔
177
                             size_t /*poll_bits*/,
178
                             std::chrono::milliseconds /*poll_timeout*/) {
179
   /* no way to add entropy */
180
   return 0;
1✔
181
}
182

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