7#include <botan/processor_rng.h>
9#include <botan/internal/cpuid.h>
10#include <botan/internal/loadstor.h>
12#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) && !defined(BOTAN_USE_GCC_INLINE_ASM)
13 #include <immintrin.h>
20#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
25const size_t HWRNG_RETRIES = 10;
27#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
35const size_t HWRNG_RETRIES = 10;
41const size_t HWRNG_RETRIES = 512;
44#if defined(BOTAN_TARGET_ARCH_IS_X86_32)
45typedef uint32_t hwrng_output;
47typedef uint64_t hwrng_output;
50hwrng_output read_hwrng(
bool& success) {
51 hwrng_output output = 0;
54#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
56 #if defined(BOTAN_USE_GCC_INLINE_ASM)
58 asm volatile(
"rdrand %0; adcl $0,%1" :
"=r"(output),
"=r"(cf) :
"0"(output),
"1"(cf) :
"cc");
59 #elif defined(BOTAN_TARGET_ARCH_IS_X86_32)
60 cf = _rdrand32_step(&output);
62 cf = _rdrand64_step(&output);
66#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
75 asm volatile(
"darn %0, 1" :
"=r"(output));
76 asm volatile(
"darn %0, 1" :
"=r"(output2));
78 if((~output) != 0 && (~output2) != 0) {
92hwrng_output read_hwrng() {
93 for(
size_t i = 0; i < HWRNG_RETRIES; ++i) {
95 hwrng_output output = read_hwrng(success);
102 throw PRNG_Unseeded(
"Processor RNG instruction failed to produce output within expected iterations");
109#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
110 return CPUID::has_rdrand();
111#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
112 return CPUID::has_darn_rng();
119#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
121#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
128void Processor_RNG::fill_bytes_with_input(std::span<uint8_t> out, std::span<const uint8_t> in) {
132 while(out.size() >=
sizeof(hwrng_output)) {
133 const hwrng_output r = read_hwrng();
135 out = out.subspan(
sizeof(hwrng_output));
140 const hwrng_output r = read_hwrng();
141 uint8_t hwrng_bytes[
sizeof(hwrng_output)];
144 for(
size_t i = 0; i != out.size(); ++i) {
145 out[i] = hwrng_bytes[i];
152 throw Invalid_State(
"Current CPU does not support RNG instruction");
158 std::chrono::milliseconds ) {
size_t reseed(Entropy_Sources &, size_t, std::chrono::milliseconds) override
std::string name() const override
constexpr auto store_le(ParamTs &&... params)