summaryrefslogtreecommitdiff
path: root/rdrand.h
blob: 8fdaa1480b86cdc3b276eaa427d6bbb0761ee6f0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// rdrand.h - written and placed in public domain by Jeffrey Walton and Uri Blumenthal.

//! \file rdrand.h
//! \brief Classes for RDRAND and RDSEED
//! \since Crypto++ 5.6.3

#ifndef CRYPTOPP_RDRAND_H
#define CRYPTOPP_RDRAND_H

#include "cryptlib.h"

// 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, 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.

// 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)

//! \brief Exception thrown when a RDRAND generator encounters
//!    a generator related error.
//! \since Crypto++ 5.6.3
class RDRAND_Err : public Exception
{
public:
    RDRAND_Err(const std::string &operation)
        : Exception(OTHER_ERROR, "RDRAND: " + operation + " operation failed") {}
};

//! \brief Hardware generated random numbers using RDRAND instruction
//! \sa MaurerRandomnessTest() for random bit generators
//! \since Crypto++ 5.6.3
class RDRAND : public RandomNumberGenerator
{
public:
    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
//!    a generator related error.
//! \since Crypto++ 5.6.3
class RDSEED_Err : public Exception
{
public:
    RDSEED_Err(const std::string &operation)
        : Exception(OTHER_ERROR, "RDSEED: " + operation + " operation failed") {}
};

//! \brief Hardware generated random numbers using RDSEED instruction
//! \sa MaurerRandomnessTest() for random bit generators
//! \since Crypto++ 5.6.3
class RDSEED : public RandomNumberGenerator
{
public:
    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);
    }
};

NAMESPACE_END

#endif // CRYPTOPP_RDRAND_H