aboutsummaryrefslogtreecommitdiff
path: root/src/random.cpp
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2017-06-14 15:22:08 +0200
committerWladimir J. van der Laan <laanwj@gmail.com>2017-06-14 15:22:15 +0200
commitb63be2c6852f055e60185aea93ceb4a1ef798c40 (patch)
tree887468c3240bf2acb2ffa66710bc1010613addf4 /src/random.cpp
parent1ad3d4e1261f4a444d982a1470c257c78233bda3 (diff)
parentcb24c8539d1098d1a61605b452ecfa11a693320d (diff)
downloadbitcoin-b63be2c6852f055e60185aea93ceb4a1ef798c40.tar.xz
Merge #10377: Use rdrand as entropy source on supported platforms
cb24c85 Use rdrand as entropy source on supported platforms (Pieter Wuille) Tree-SHA512: c42eaa01a14e6bc097c70b6bf8540d61854c2f76cb32be69c2a3c411a126f7b4bf4a4486e4493c4cc367cc689319abde0d4adb799d29a54fd3e81767ce0766fc
Diffstat (limited to 'src/random.cpp')
-rw-r--r--src/random.cpp68
1 files changed, 68 insertions, 0 deletions
diff --git a/src/random.cpp b/src/random.cpp
index e1ccfa5f24..7916643263 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -65,6 +65,64 @@ static inline int64_t GetPerformanceCounter()
#endif
}
+
+#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
+static std::atomic<bool> hwrand_initialized{false};
+static bool rdrand_supported = false;
+static constexpr uint32_t CPUID_F1_ECX_RDRAND = 0x40000000;
+static void RDRandInit()
+{
+ //! When calling cpuid function #1, ecx register will have this set if RDRAND is available.
+ // Avoid clobbering ebx, as that is used for PIC on x86.
+ uint32_t eax, tmp, ecx, edx;
+ __asm__ ("mov %%ebx, %1; cpuid; mov %1, %%ebx": "=a"(eax), "=g"(tmp), "=c"(ecx), "=d"(edx) : "a"(1));
+ if (ecx & CPUID_F1_ECX_RDRAND) {
+ LogPrintf("Using RdRand as entropy source\n");
+ rdrand_supported = true;
+ }
+ hwrand_initialized.store(true);
+}
+#else
+static void RDRandInit() {}
+#endif
+
+static bool GetHWRand(unsigned char* ent32) {
+#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
+ assert(hwrand_initialized.load(std::memory_order_relaxed));
+ if (rdrand_supported) {
+ uint8_t ok;
+ // Not all assemblers support the rdrand instruction, write it in hex.
+#ifdef __i386__
+ for (int iter = 0; iter < 4; ++iter) {
+ uint32_t r1, r2;
+ __asm__ volatile (".byte 0x0f, 0xc7, 0xf0;" // rdrand %eax
+ ".byte 0x0f, 0xc7, 0xf2;" // rdrand %edx
+ "setc %2" :
+ "=a"(r1), "=d"(r2), "=q"(ok) :: "cc");
+ if (!ok) return false;
+ WriteLE32(ent32 + 8 * iter, r1);
+ WriteLE32(ent32 + 8 * iter + 4, r2);
+ }
+#else
+ uint64_t r1, r2, r3, r4;
+ __asm__ volatile (".byte 0x48, 0x0f, 0xc7, 0xf0, " // rdrand %rax
+ "0x48, 0x0f, 0xc7, 0xf3, " // rdrand %rbx
+ "0x48, 0x0f, 0xc7, 0xf1, " // rdrand %rcx
+ "0x48, 0x0f, 0xc7, 0xf2; " // rdrand %rdx
+ "setc %4" :
+ "=a"(r1), "=b"(r2), "=c"(r3), "=d"(r4), "=q"(ok) :: "cc");
+ if (!ok) return false;
+ WriteLE64(ent32, r1);
+ WriteLE64(ent32 + 8, r2);
+ WriteLE64(ent32 + 16, r3);
+ WriteLE64(ent32 + 24, r4);
+#endif
+ return true;
+ }
+#endif
+ return false;
+}
+
void RandAddSeed()
{
// Seed with CPU performance counter
@@ -255,6 +313,11 @@ void GetStrongRandBytes(unsigned char* out, int num)
GetOSRand(buf);
hasher.Write(buf, 32);
+ // Third source: HW RNG, if available.
+ if (GetHWRand(buf)) {
+ hasher.Write(buf, 32);
+ }
+
// Combine with and update state
{
std::unique_lock<std::mutex> lock(cs_rng_state);
@@ -381,3 +444,8 @@ FastRandomContext::FastRandomContext(bool fDeterministic) : requires_seed(!fDete
uint256 seed;
rng.SetKey(seed.begin(), 32);
}
+
+void RandomInit()
+{
+ RDRandInit();
+}