summaryrefslogtreecommitdiff
path: root/rdrand.h
diff options
context:
space:
mode:
authorJeffrey Walton <noloader@gmail.com>2017-03-07 03:57:23 -0500
committerJeffrey Walton <noloader@gmail.com>2017-03-07 03:57:23 -0500
commit14d92f9eba81191e3537ac14ff21d84ef7405e9c (patch)
tree1172fe3ce930b17822242c9a3f6c3fe28a17842f /rdrand.h
parent1e5d6ee8d4f1dd2dd7d89bc6e2dd5391fd853908 (diff)
downloadcryptopp-git-14d92f9eba81191e3537ac14ff21d84ef7405e9c.tar.gz
Improve performance of RDRAND and RDSEED (Issue 387)
Diffstat (limited to 'rdrand.h')
-rw-r--r--rdrand.h226
1 files changed, 84 insertions, 142 deletions
diff --git a/rdrand.h b/rdrand.h
index 5e602697..10369b1c 100644
--- a/rdrand.h
+++ b/rdrand.h
@@ -9,16 +9,24 @@
#include "cryptlib.h"
-// This file (and friends) provides both RDRAND and RDSEED, but its somewhat
-// experimental. They were added at Crypto++ 5.6.3. At compile time, it
-// indirectly uses CRYPTOPP_BOOL_{X86|X32|X64} (via CRYPTOPP_CPUID_AVAILABLE)
+// This file (and friends) provides both RDRAND and RDSEED. They were added at
+// Crypto++ 5.6.3. At compile time, it uses CRYPTOPP_BOOL_{X86|X32|X64}
// to select an implementation or "throw NotImplemented". At runtime, the
// class uses the result of CPUID to determine if RDRAND or RDSEED are
-// available. If not available, a lazy throw strategy is used. I.e., the
-// throw is deferred until GenerateBlock() is called.
+// available. If not available, then a SIGILL will result.
+// The original classes accepted a retry count. Retries were superflous for
+// RDRAND, and RDSEED encountered a failure about 1 in 256 bytes depending
+// on the processor. Retries were removed at Crypto++ 6.0 because the
+// functions always fulfill the request.
-// Microsoft added RDRAND in August 2012, VS2012. GCC added RDRAND in December 2010, GCC 4.6.
-// Clang added RDRAND in July 2012, Clang 3.2. Intel added RDRAND in September 2011, ICC 12.1.
+// Throughput varies wildly depending on processor and manufacturer. A Core i5 or
+// Core i7 RDRAND can generate at over 200 MiB/s. A low end Celeron may perform
+// RDRAND at 7 MiB/s. RDSEED performs at about 1/4 to 1/2 the rate of RDRAND.
+// AMD RDRAND performed poorly during testing with Athlon X4 845 (Bulldozer v4).
+
+// Microsoft added RDRAND in August 2012, VS2012; RDSEED in October 2013, VS2013.
+// GCC added RDRAND in December 2010, GCC 4.6. LLVM added RDRAND in July 2012, Clang 3.2.
+// Intel added RDRAND in September 2011, ICC 12.1.
NAMESPACE_BEGIN(CryptoPP)
@@ -28,8 +36,8 @@ NAMESPACE_BEGIN(CryptoPP)
class RDRAND_Err : public Exception
{
public:
- RDRAND_Err(const std::string &operation)
- : Exception(OTHER_ERROR, "RDRAND: " + operation + " operation failed") {}
+ RDRAND_Err(const std::string &operation)
+ : Exception(OTHER_ERROR, "RDRAND: " + operation + " operation failed") {}
};
//! \brief Hardware generated random numbers using RDRAND instruction
@@ -38,73 +46,39 @@ public:
class RDRAND : public RandomNumberGenerator
{
public:
- virtual ~RDRAND() {}
-
- std::string AlgorithmName() const {return "RDRAND";}
-
- //! \brief Construct a RDRAND generator
- //! \param retries the number of retries for failed calls to the hardware
- //! \details RDRAND() constructs a generator with a maximum number of retires
- //! for failed generation attempts.
- //! \details According to DJ of Intel, the Intel RDRAND circuit does not underflow.
- //! If it did hypothetically underflow, then it would return 0 for the random value.
- //! AMD's RDRAND implementation appears to provide the same behavior except the
- //! values are not generated consistent with FIPS 140.
- RDRAND(unsigned int retries = 4) : m_retries(retries) {}
-
- //! \brief Retrieve the number of retries used by the generator
- //! \returns the number of times GenerateBlock() will attempt to recover from a failed generation
- unsigned int GetRetries() const
- {
- return m_retries;
- }
-
- //! \brief Set the number of retries used by the generator
- //! \param retries number of times GenerateBlock() will attempt to recover from a failed generation
- void SetRetries(unsigned int retries)
- {
- m_retries = retries;
- }
-
- //! \brief Generate random array of bytes
- //! \param output the byte buffer
- //! \param size the length of the buffer, in bytes
-#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
- virtual void GenerateBlock(byte *output, size_t size);
-#else
- virtual void GenerateBlock(byte *output, size_t size) {
- CRYPTOPP_UNUSED(output), CRYPTOPP_UNUSED(size);
- throw NotImplemented("RDRAND: rdrand is not available on this platform");
- }
-#endif
-
- //! \brief Generate and discard n bytes
- //! \param n the number of bytes to generate and discard
- //! \details the RDSEED generator discards words, not bytes. If n is
- //! not a multiple of a machine word, then it is rounded up to
- //! that size.
-#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
- virtual void DiscardBytes(size_t n);
-#else
- virtual void DiscardBytes(size_t n) {
- CRYPTOPP_UNUSED(n);
- throw NotImplemented("RDRAND: rdrand is not available on this platform");
- }
-#endif
-
- //! \brief Update RNG state with additional unpredictable values
- //! \param input unused
- //! \param length unused
- //! \details The operation is a nop for this generator.
- virtual void IncorporateEntropy(const byte *input, size_t length)
- {
- // Override to avoid the base class' throw.
- CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length);
- // CRYPTOPP_ASSERT(0); // warn in debug builds
- }
-
-private:
- unsigned int m_retries;
+ CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "RDRAND"; }
+
+ virtual ~RDRAND() {}
+
+ //! \brief Construct a RDRAND generator
+ //! \param retries the number of retries for failed calls to the hardware
+ //! \details According to DJ of Intel, the Intel RDRAND circuit does not underflow.
+ //! If it did hypothetically underflow, then it would return 0 for the random value.
+ //! AMD's RDRAND implementation appears to provide the same behavior except the
+ //! values are not generated consistent with FIPS 140.
+ RDRAND() {}
+
+ //! \brief Generate random array of bytes
+ //! \param output the byte buffer
+ //! \param size the length of the buffer, in bytes
+ virtual void GenerateBlock(byte *output, size_t size);
+
+ //! \brief Generate and discard n bytes
+ //! \param n the number of bytes to generate and discard
+ //! \details the RDSEED generator discards words, not bytes. If n is
+ //! not a multiple of a machine word, then it is rounded up to
+ //! that size.
+ virtual void DiscardBytes(size_t n);
+
+ //! \brief Update RNG state with additional unpredictable values
+ //! \param input unused
+ //! \param length unused
+ //! \details The operation is a nop for this generator.
+ virtual void IncorporateEntropy(const byte *input, size_t length)
+ {
+ // Override to avoid the base class' throw.
+ CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length);
+ }
};
//! \brief Exception thrown when a RDSEED generator encounters
@@ -113,8 +87,8 @@ private:
class RDSEED_Err : public Exception
{
public:
- RDSEED_Err(const std::string &operation)
- : Exception(OTHER_ERROR, "RDSEED: " + operation + " operation failed") {}
+ RDSEED_Err(const std::string &operation)
+ : Exception(OTHER_ERROR, "RDSEED: " + operation + " operation failed") {}
};
//! \brief Hardware generated random numbers using RDSEED instruction
@@ -123,72 +97,40 @@ public:
class RDSEED : public RandomNumberGenerator
{
public:
- virtual ~RDSEED() {}
-
- std::string AlgorithmName() const {return "RDSEED";}
-
- //! \brief Construct a RDSEED generator
- //! \param retries the number of retries for failed calls to the hardware
- //! \details RDSEED() constructs a generator with a maximum number of retires
- //! for failed generation attempts.
- //! \details Empirical testing under a 6th generaton i7 (6200U) shows RDSEED fails
- //! to fulfill requests at about once every for every 256 bytes requested.
- //! The default retries reflects the expected ceiling when requesting 10,000 bytes.
- RDSEED(unsigned int retries = 64) : m_retries(retries) {}
-
- //! \brief Retrieve the number of retries used by the generator
- //! \returns the number of times GenerateBlock() will attempt to recover from a failed generation
- unsigned int GetRetries() const
- {
- return m_retries;
- }
-
- //! \brief Set the number of retries used by the generator
- //! \param retries number of times GenerateBlock() will attempt to recover from a failed generation
- void SetRetries(unsigned int retries)
- {
- m_retries = retries;
- }
-
- //! \brief Generate random array of bytes
- //! \param output the byte buffer
- //! \param size the length of the buffer, in bytes
-#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
- virtual void GenerateBlock(byte *output, size_t size);
-#else
- virtual void GenerateBlock(byte *output, size_t size) {
- CRYPTOPP_UNUSED(output), CRYPTOPP_UNUSED(size);
- throw NotImplemented("RDSEED: rdseed is not available on this platform");
- }
-#endif
-
- //! \brief Generate and discard n bytes
- //! \param n the number of bytes to generate and discard
- //! \details the RDSEED generator discards words, not bytes. If n is
- //! not a multiple of a machine word, then it is rounded up to
- //! that size.
-#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
- virtual void DiscardBytes(size_t n);
-#else
- virtual void DiscardBytes(size_t n) {
- CRYPTOPP_UNUSED(n);
- throw NotImplemented("RDSEED: rdseed is not available on this platform");
- }
-#endif
-
- //! \brief Update RNG state with additional unpredictable values
- //! \param input unused
- //! \param length unused
- //! \details The operation is a nop for this generator.
- virtual void IncorporateEntropy(const byte *input, size_t length)
- {
- // Override to avoid the base class' throw.
- CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length);
- // CRYPTOPP_ASSERT(0); // warn in debug builds
- }
+ CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "RDSEED"; }
+
+ virtual ~RDSEED() {}
+
+ //! \brief Construct a RDSEED generator
+ //! \details Empirical testing under a 6th generaton i7 (6200U) shows RDSEED fails
+ //! to fulfill requests at about once every for every 256 bytes requested.
+ //! The generator runs about 4 times slower than RDRAND.
+ RDSEED() {}
+
+ //! \brief Generate random array of bytes
+ //! \param output the byte buffer
+ //! \param size the length of the buffer, in bytes
+ virtual void GenerateBlock(byte *output, size_t size);
+
+ //! \brief Generate and discard n bytes
+ //! \param n the number of bytes to generate and discard
+ //! \details the RDSEED generator discards words, not bytes. If n is
+ //! not a multiple of a machine word, then it is rounded up to
+ //! that size.
+ virtual void DiscardBytes(size_t n);
+
+ //! \brief Update RNG state with additional unpredictable values
+ //! \param input unused
+ //! \param length unused
+ //! \details The operation is a nop for this generator.
+ virtual void IncorporateEntropy(const byte *input, size_t length)
+ {
+ // Override to avoid the base class' throw.
+ CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length);
+ }
private:
- unsigned int m_retries;
+ unsigned int m_retries;
};
NAMESPACE_END