Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/compat/cpuid.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,20 @@ void static inline GetCPUID(uint32_t leaf, uint32_t subleaf, uint32_t& a, uint32
}

#endif // defined(__x86_64__) || defined(__amd64__) || defined(__i386__)

#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
#define HAVE_GETCPUID

#include <intrin.h>
void static inline GetCPUID(uint32_t leaf, uint32_t subleaf, uint32_t& a, uint32_t& b, uint32_t& c, uint32_t& d)
{
int regs[4];
__cpuidex(regs, leaf, subleaf);
a = regs[0];
b = regs[1];
c = regs[2];
d = regs[3];
}

#endif // defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
#endif // BITCOIN_COMPAT_CPUID_H
42 changes: 40 additions & 2 deletions src/random.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,25 @@ static uint64_t GetRdRand() noexcept
if (ok) break;
}
return r1;
#elif defined(_MSC_VER) && defined(_M_X64)
uint64_t r1 = 0; // See above why we initialize to 0.
for (int i = 0; i < 10; ++i) {
uint8_t ok = _rdrand64_step(&r1);
if (ok) break;
}
return r1;
#elif defined(_MSC_VER) && defined(_M_IX86)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really care about x86 32 bit here? We don't build binaries for it anymore. I'm also not sure if there are actually existing x86 32-bit CPUs that support these instructions.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have 32-bit x86 support only because bitcoin currently supports 32-bit x86 rd instructions and I am just extending what already exists to the MSVC compiler. If it is decided that bitcoin-core will no longer target 32-bit x86 than it seems reasonable to remove.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can put together a PR which removes 32-bit rdrand and rdseed support if that is something you think would be mergeable.

uint32_t r1 = 0; // See above why we initialize to 0.
uint32_t r2 = 0;
for (int i = 0; i < 10; ++i) {
uint8_t ok = _rdrand32_step(&r1);
if (ok) break;
}
for (int i = 0; i < 10; ++i) {
int ok = _rdrand32_step(&r2);
if (ok) break;
}
return (((uint64_t)r2) << 32) | r1;
#else
#error "RdRand is only supported on x86 and x86_64"
#endif
Expand Down Expand Up @@ -170,6 +189,25 @@ static uint64_t GetRdSeed() noexcept
__asm__ volatile ("pause");
} while(true);
return r1;
#elif defined(_MSC_VER) && defined(_M_X64)
uint64_t r1 = 0; // See above why we initialize to 0.
do {
uint8_t ok = _rdseed64_step(&r1);
if (ok) break;
} while(true);
return r1;
#elif defined(_MSC_VER) && defined(_M_IX86)
uint32_t r1 = 0; // See above why we initialize to 0.
uint32_t r2 = 0;
for (int i = 0; i < 10; ++i) {
uint8_t ok = _rdseed32_step(&r1);
if (ok) break;
}
for (int i = 0; i < 10; ++i) {
int ok = _rdseed32_step(&r2);
if (ok) break;
}
return (((uint64_t)r2) << 32) | r1;
#else
#error "RdSeed is only supported on x86 and x86_64"
#endif
Expand All @@ -187,7 +225,7 @@ static void ReportHardwareRand() {}

/** Add 64 bits of entropy gathered from hardware to hasher. Do nothing if not supported. */
static void SeedHardwareFast(CSHA512& hasher) noexcept {
#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__) || (defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)))
if (g_rdrand_supported) {
uint64_t out = GetRdRand();
hasher.Write((const unsigned char*)&out, sizeof(out));
Expand All @@ -198,7 +236,7 @@ static void SeedHardwareFast(CSHA512& hasher) noexcept {

/** Add 256 bits of entropy gathered from hardware to hasher. Do nothing if not supported. */
static void SeedHardwareSlow(CSHA512& hasher) noexcept {
#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__) || (defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)))
// When we want 256 bits of entropy, prefer RdSeed over RdRand, as it's
// guaranteed to produce independent randomness on every call.
if (g_rdseed_supported) {
Expand Down
86 changes: 86 additions & 0 deletions src/test/hwrand_tests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright (c) 2011-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
#include <test/util/setup_common.h>
#include <boost/test/unit_test.hpp>

#include <random.cpp>

using namespace std;

BOOST_FIXTURE_TEST_SUITE(hwrand_tests, BasicTestingSetup)

BOOST_AUTO_TEST_CASE(rdx86seedhwslow_test)
{
const size_t DIGEST_LEN = 512/8; // 512 bits = 64 bytes

unsigned char emptyoutput[DIGEST_LEN];
memset(emptyoutput, 0, DIGEST_LEN);
CSHA512 emptyhasher;
emptyhasher.Finalize(emptyoutput);

for (int i = 0; i < 5; i++)
{
CSHA512 hasher;
unsigned char output[DIGEST_LEN];
memset(output, 0, DIGEST_LEN);

SeedHardwareSlow(hasher);
hasher.Finalize(output);

#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__) || (defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)))
bool isNotEqual = (memcmp(output, emptyoutput, DIGEST_LEN) != 0);
if (g_rdseed_supported)
{
BOOST_CHECK(isNotEqual);
}
else
{
BOOST_CHECK(!isNotEqual);
}
#else
// RDRand not supported on this platform so the hasher should have no data written to it
bool isEqual = (memcmp(output, emptyoutput, DIGEST_LEN) == 0);
BOOST_CHECK(isEqual);
#endif
}
}

BOOST_AUTO_TEST_CASE(rdx86seedhwfast_test)
{
const size_t DIGEST_LEN = 512/8; // 512 bits = 64 bytes

unsigned char emptyoutput[DIGEST_LEN];
memset(emptyoutput, 0, DIGEST_LEN);
CSHA512 emptyhasher;
emptyhasher.Finalize(emptyoutput);

for (int i = 0; i < 5; i++)
{
CSHA512 hasher;
unsigned char output[DIGEST_LEN];
memset(output, 0, DIGEST_LEN);

SeedHardwareFast(hasher);
hasher.Finalize(output);

#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__) || (defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)))
bool isNotEqual = (memcmp(output, emptyoutput, DIGEST_LEN) != 0);
if (g_rdrand_supported)
{
BOOST_CHECK(isNotEqual);
}
else
{
BOOST_CHECK(!isNotEqual);
}
#else
// RDRand not supported on this platform so the hasher should have no data written to it
bool isEqual = (memcmp(output, emptyoutput, DIGEST_LEN) == 0);
BOOST_CHECK(isEqual);
#endif
}
}

BOOST_AUTO_TEST_SUITE_END()