summaryrefslogtreecommitdiff
path: root/rdrand.h
blob: 41e4921e9f0dfbf24ec54254aa0af26bcbad5f12 (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
136
137
138
139
140
141
142
143
144
145
// 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 class file 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
//   constructor will throw RDRAND_Err or RDSEED_Err if a generator is
//   is not available.
// 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
//   GenerateBlock unconditionally retries and always fulfills the request.

// Throughput varies wildly depending on processor and manufacturer. A Core i5 or
//   Core i7 RDRAND can generate at over 200 MiB/s. It is below the theroetical
//   maximum, but it takes about 5 instructions to generate, retry and store a
//   result. A low-end Celeron may perform RDRAND at about 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. The Bulldozer v4 only performed at 1 MiB/s.

// 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
    /// \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.
     /// \throws RDRAND_Err if the random number generator is not available
    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);
    }

    std::string AlgorithmProvider() const {
        return "RDRAND";
    }
};

/// \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.
     /// \throws RDSEED_Err if the random number generator is not available
    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);
    }

    std::string AlgorithmProvider() const {
        return "RDSEED";
    }
};

NAMESPACE_END

#endif // CRYPTOPP_RDRAND_H