Skip to content

Commit

Permalink
Add support for RNDR/RNDRRS for aarch64 on Linux
Browse files Browse the repository at this point in the history
This checks whether the ARMv8.5 extensions RNDR and RNDRRS
are available and uses them for random entropy purposes.

They are functionally identical to the x86 RDRAND/RDSEED
extensions and are used in a similar manner.
  • Loading branch information
john-moffett committed Sep 29, 2023
1 parent adc41cf commit aee5404
Showing 1 changed file with 73 additions and 0 deletions.
73 changes: 73 additions & 0 deletions src/random.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@
#ifdef HAVE_SYSCTL_ARND
#include <sys/sysctl.h>
#endif
#if defined(HAVE_STRONG_GETAUXVAL) && defined(__aarch64__)
#include <sys/auxv.h>
#endif

[[noreturn]] static void RandFailure()
{
Expand Down Expand Up @@ -175,6 +178,62 @@ static uint64_t GetRdSeed() noexcept
#endif
}

#elif defined(__aarch64__) && defined(HWCAP2_RNG)

static bool g_rndr_supported = false;

static void InitHardwareRand()
{
if (getauxval(AT_HWCAP2) & HWCAP2_RNG) {
g_rndr_supported = true;
}
}

static void ReportHardwareRand()
{
// This must be done in a separate function, as InitHardwareRand() may be indirectly called
// from global constructors, before logging is initialized.
if (g_rndr_supported) {
LogPrintf("Using RNDR and RNDRRS as additional entropy sources\n");
}
}

/** Read 64 bits of entropy using rndr.
*
* Must only be called when RNDR is supported.
*/
static uint64_t GetRNDR() noexcept
{
uint8_t ok;
uint64_t r1;
do {
// https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers/RNDR--Random-Number
__asm__ volatile("mrs %0, s3_3_c2_c4_0; cset %w1, ne;"
: "=r"(r1), "=r"(ok)::"cc");
if (ok) break;
__asm__ volatile("yield");
} while (true);
return r1;
}

/** Read 64 bits of entropy using rndrrs.
*
* Must only be called when RNDRRS is supported.
*/
static uint64_t GetRNDRRS() noexcept
{
uint8_t ok;
uint64_t r1;
do {
// https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers/RNDRRS--Reseeded-Random-Number
__asm__ volatile("mrs %0, s3_3_c2_c4_1; cset %w1, ne;"
: "=r"(r1), "=r"(ok)::"cc");
if (ok) break;
__asm__ volatile("yield");
} while (true);
return r1;
}

#else
/* Access to other hardware random number generators could be added here later,
* assuming it is sufficiently fast (in the order of a few hundred CPU cycles).
Expand All @@ -193,6 +252,12 @@ static void SeedHardwareFast(CSHA512& hasher) noexcept {
hasher.Write((const unsigned char*)&out, sizeof(out));
return;
}
#elif defined(__aarch64__) && defined(HWCAP2_RNG)
if (g_rndr_supported) {
uint64_t out = GetRNDR();
hasher.Write((const unsigned char*)&out, sizeof(out));
return;
}
#endif
}

Expand All @@ -218,6 +283,14 @@ static void SeedHardwareSlow(CSHA512& hasher) noexcept {
}
return;
}
#elif defined(__aarch64__) && defined(HWCAP2_RNG)
if (g_rndr_supported) {
for (int i = 0; i < 4; ++i) {
uint64_t out = GetRNDRRS();
hasher.Write((const unsigned char*)&out, sizeof(out));
}
return;
}
#endif
}

Expand Down

0 comments on commit aee5404

Please sign in to comment.