Skip to content

Commit c8a883a

Browse files
committed
Merge bitcoin#26839: Add support for RNDR/RNDRRS for AArch64 on Linux
aee5404 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](torvalds/linux@1a50ec0) 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 bitcoin#26796. As noted in that issue, OpenSSL [added support](openssl/openssl#15361) for these extensions a little over a year ago. ACKs for top commit: achow101: ACK aee5404 laanwj: Tested ACK aee5404 Tree-SHA512: 1c1eb345d6690f5307a87e9bac8f06a0d1fdc7ca35db38fa22192510a44289a03252e4677dc7cbf731a27e6e3a9a4e42b6eb4149fe063bc1c905eb2536cdb1d3
2 parents e773396 + aee5404 commit c8a883a

File tree

1 file changed

+73
-0
lines changed

1 file changed

+73
-0
lines changed

src/random.cpp

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@
3838
#ifdef HAVE_SYSCTL_ARND
3939
#include <sys/sysctl.h>
4040
#endif
41+
#if defined(HAVE_STRONG_GETAUXVAL) && defined(__aarch64__)
42+
#include <sys/auxv.h>
43+
#endif
4144

4245
[[noreturn]] static void RandFailure()
4346
{
@@ -173,6 +176,62 @@ static uint64_t GetRdSeed() noexcept
173176
#endif
174177
}
175178

179+
#elif defined(__aarch64__) && defined(HWCAP2_RNG)
180+
181+
static bool g_rndr_supported = false;
182+
183+
static void InitHardwareRand()
184+
{
185+
if (getauxval(AT_HWCAP2) & HWCAP2_RNG) {
186+
g_rndr_supported = true;
187+
}
188+
}
189+
190+
static void ReportHardwareRand()
191+
{
192+
// This must be done in a separate function, as InitHardwareRand() may be indirectly called
193+
// from global constructors, before logging is initialized.
194+
if (g_rndr_supported) {
195+
LogPrintf("Using RNDR and RNDRRS as additional entropy sources\n");
196+
}
197+
}
198+
199+
/** Read 64 bits of entropy using rndr.
200+
*
201+
* Must only be called when RNDR is supported.
202+
*/
203+
static uint64_t GetRNDR() noexcept
204+
{
205+
uint8_t ok;
206+
uint64_t r1;
207+
do {
208+
// https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers/RNDR--Random-Number
209+
__asm__ volatile("mrs %0, s3_3_c2_c4_0; cset %w1, ne;"
210+
: "=r"(r1), "=r"(ok)::"cc");
211+
if (ok) break;
212+
__asm__ volatile("yield");
213+
} while (true);
214+
return r1;
215+
}
216+
217+
/** Read 64 bits of entropy using rndrrs.
218+
*
219+
* Must only be called when RNDRRS is supported.
220+
*/
221+
static uint64_t GetRNDRRS() noexcept
222+
{
223+
uint8_t ok;
224+
uint64_t r1;
225+
do {
226+
// https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers/RNDRRS--Reseeded-Random-Number
227+
__asm__ volatile("mrs %0, s3_3_c2_c4_1; cset %w1, ne;"
228+
: "=r"(r1), "=r"(ok)::"cc");
229+
if (ok) break;
230+
__asm__ volatile("yield");
231+
} while (true);
232+
return r1;
233+
}
234+
176235
#else
177236
/* Access to other hardware random number generators could be added here later,
178237
* assuming it is sufficiently fast (in the order of a few hundred CPU cycles).
@@ -191,6 +250,12 @@ static void SeedHardwareFast(CSHA512& hasher) noexcept {
191250
hasher.Write((const unsigned char*)&out, sizeof(out));
192251
return;
193252
}
253+
#elif defined(__aarch64__) && defined(HWCAP2_RNG)
254+
if (g_rndr_supported) {
255+
uint64_t out = GetRNDR();
256+
hasher.Write((const unsigned char*)&out, sizeof(out));
257+
return;
258+
}
194259
#endif
195260
}
196261

@@ -216,6 +281,14 @@ static void SeedHardwareSlow(CSHA512& hasher) noexcept {
216281
}
217282
return;
218283
}
284+
#elif defined(__aarch64__) && defined(HWCAP2_RNG)
285+
if (g_rndr_supported) {
286+
for (int i = 0; i < 4; ++i) {
287+
uint64_t out = GetRNDRRS();
288+
hasher.Write((const unsigned char*)&out, sizeof(out));
289+
}
290+
return;
291+
}
219292
#endif
220293
}
221294

0 commit comments

Comments
 (0)