aboutsummaryrefslogtreecommitdiff
path: root/src/random.cpp
diff options
context:
space:
mode:
authorAndrew Chow <github@achow101.com>2023-11-07 15:00:12 -0500
committerAndrew Chow <github@achow101.com>2023-11-07 15:00:38 -0500
commitc8a883a4123ab466f9d911ee2865625ba5314c9e (patch)
treed9c8b502983af14466e1a143c4246e0f397d9022 /src/random.cpp
parente77339632efb8faf47deae7dc4fbd82bdc130614 (diff)
parentaee5404e02e203a256c1a97b629b9b107cc8bb07 (diff)
Merge bitcoin/bitcoin#26839: Add support for RNDR/RNDRRS for AArch64 on Linux
aee5404e02e203a256c1a97b629b9b107cc8bb07 Add support for RNDR/RNDRRS for aarch64 on Linux (John Moffett) Pull request description: This checks whether the ARMv8.5-A optional TRNG extensions [RNDR](https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers/RNDR--Random-Number) and [RNDRRS](https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers/RNDRRS--Reseeded-Random-Number) are available and, if they are, uses them for random entropy purposes. They are nearly functionally identical to the x86 RDRAND/RDSEED extensions and are used in a similar manner. Currently, there [appears to be](https://marcin.juszkiewicz.com.pl/download/tables/arm-socs.html) only one actual hardware implementation -- the Amazon Graviton 3. (See the `rnd` column in the link.) However, future hardware implementations may become available. It's not possible to directly query for the capability in userspace, but the Linux kernel [added support](https://github.com/torvalds/linux/commit/1a50ec0b3b2e9a83f1b1245ea37a853aac2f741c) for querying the extension via `getauxval` in version 5.6 (in 2020), so this is limited to Linux-only for now. Reviewers may want to launch any of the `c7g` instances from AWS to test the Graviton 3 hardware. Alternatively, QEMU emulates these opcodes for `aarch64` with CPU setting `max`. Output from Graviton 3 hardware: ``` ubuntu@ip:~/bitcoin$ src/bitcoind -regtest 2023-01-06T20:01:48Z Bitcoin Core version v24.99.0-3670266ce89a (release build) 2023-01-06T20:01:48Z Using the 'arm_shani(1way,2way)' SHA256 implementation 2023-01-06T20:01:48Z Using RNDR and RNDRRS as additional entropy sources 2023-01-06T20:01:48Z Default data directory /home/ubuntu/.bitcoin ``` Graviton 2 (doesn't support extensions): ``` ubuntu@ip:~/bitcoin$ src/bitcoind -regtest 2023-01-06T20:05:04Z Bitcoin Core version v24.99.0-3670266ce89a (release build) 2023-01-06T20:05:04Z Using the 'arm_shani(1way,2way)' SHA256 implementation 2023-01-06T20:05:04Z Default data directory /home/ubuntu/.bitcoin ``` This partially closes #26796. As noted in that issue, OpenSSL [added support](https://github.com/openssl/openssl/pull/15361) for these extensions a little over a year ago. ACKs for top commit: achow101: ACK aee5404e02e203a256c1a97b629b9b107cc8bb07 laanwj: Tested ACK aee5404e02e203a256c1a97b629b9b107cc8bb07 Tree-SHA512: 1c1eb345d6690f5307a87e9bac8f06a0d1fdc7ca35db38fa22192510a44289a03252e4677dc7cbf731a27e6e3a9a4e42b6eb4149fe063bc1c905eb2536cdb1d3
Diffstat (limited to 'src/random.cpp')
-rw-r--r--src/random.cpp73
1 files changed, 73 insertions, 0 deletions
diff --git a/src/random.cpp b/src/random.cpp
index 9bd8ff9f1a..ce4266a567 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -38,6 +38,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()
{
@@ -173,6 +176,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).
@@ -191,6 +250,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
}
@@ -216,6 +281,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
}