Updated MersenneTwister tests
The tests now include the first 10 elements of the sequence to ensure a properly implemented algorithm and endianess correctness.pull/416/head
parent
c1377b2955
commit
9225ca09cb
58
mersenne.h
58
mersenne.h
|
|
@ -26,7 +26,7 @@ NAMESPACE_BEGIN(CryptoPP)
|
||||||
//! required quickly. It should not be used for cryptographic purposes.
|
//! required quickly. It should not be used for cryptographic purposes.
|
||||||
//! \sa MT19937, MT19937ar
|
//! \sa MT19937, MT19937ar
|
||||||
//! \since Crypto++ 5.6.3
|
//! \since Crypto++ 5.6.3
|
||||||
template <unsigned int K, unsigned int M, unsigned int N, unsigned int F, unsigned long S>
|
template <unsigned int K, unsigned int M, unsigned int N, unsigned int F, word32 S>
|
||||||
class MersenneTwister : public RandomNumberGenerator
|
class MersenneTwister : public RandomNumberGenerator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -38,11 +38,26 @@ public:
|
||||||
//! \param seed 32-bit seed
|
//! \param seed 32-bit seed
|
||||||
//! \details Defaults to template parameter S due to changing algorithm
|
//! \details Defaults to template parameter S due to changing algorithm
|
||||||
//! parameters over time
|
//! parameters over time
|
||||||
MersenneTwister(unsigned long seed = S) : m_seed(seed), m_idx(N)
|
MersenneTwister(word32 seed = S) : m_seed(seed), m_idx(N)
|
||||||
{
|
{
|
||||||
m_state[0] = seed;
|
Reset(seed);
|
||||||
for (unsigned int i = 1; i < N+1; i++)
|
}
|
||||||
m_state[i] = word32(F * (m_state[i-1] ^ (m_state[i-1] >> 30)) + i);
|
|
||||||
|
bool CanIncorporateEntropy() const {return true;}
|
||||||
|
|
||||||
|
//! \brief Update RNG state with additional unpredictable values
|
||||||
|
//! \param input the entropy to add to the generator
|
||||||
|
//! \param length the size of the input buffer
|
||||||
|
//! \details MersenneTwister uses the first 32-bits of <tt>input</tt> to reseed the
|
||||||
|
//! generator. If fewer bytes are provided, then the seed is padded with 0's.
|
||||||
|
void IncorporateEntropy(const byte *input, size_t length)
|
||||||
|
{
|
||||||
|
word32 temp = 0;
|
||||||
|
::memcpy(&temp, input, STDMIN(sizeof(temp), length));
|
||||||
|
Reset(temp);
|
||||||
|
|
||||||
|
// Wipe temp
|
||||||
|
SecureWipeArray(&temp, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \brief Generate random array of bytes
|
//! \brief Generate random array of bytes
|
||||||
|
|
@ -58,24 +73,15 @@ public:
|
||||||
word32 temp;
|
word32 temp;
|
||||||
for (size_t i=0; i < size/4; i++, output += 4)
|
for (size_t i=0; i < size/4; i++, output += 4)
|
||||||
{
|
{
|
||||||
#if defined(CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS) && defined(IS_LITTLE_ENDIAN)
|
|
||||||
*((word32*)output) = ByteReverse(NextMersenneWord());
|
|
||||||
#elif defined(CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS)
|
|
||||||
*((word32*)output) = NextMersenneWord();
|
|
||||||
#else
|
|
||||||
temp = NextMersenneWord();
|
temp = NextMersenneWord();
|
||||||
output[3] = CRYPTOPP_GET_BYTE_AS_BYTE(temp, 0);
|
PutWord<word32>(false, LITTLE_ENDIAN_ORDER, output, temp);
|
||||||
output[2] = CRYPTOPP_GET_BYTE_AS_BYTE(temp, 1);
|
|
||||||
output[1] = CRYPTOPP_GET_BYTE_AS_BYTE(temp, 2);
|
|
||||||
output[0] = CRYPTOPP_GET_BYTE_AS_BYTE(temp, 3);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// No tail bytes
|
// No tail bytes
|
||||||
if (size%4 == 0)
|
if (size%4 == 0)
|
||||||
{
|
{
|
||||||
// Wipe temp
|
// Wipe temp
|
||||||
*((volatile word32*)&temp) = 0;
|
SecureWipeArray(&temp, 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,7 +97,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wipe temp
|
// Wipe temp
|
||||||
*((volatile word32*)&temp) = 0;
|
SecureWipeArray(&temp, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \brief Generate a random 32-bit word in the range min to max, inclusive
|
//! \brief Generate a random 32-bit word in the range min to max, inclusive
|
||||||
|
|
@ -128,6 +134,16 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
void Reset(word32 seed)
|
||||||
|
{
|
||||||
|
m_seed = seed;
|
||||||
|
m_idx = N;
|
||||||
|
|
||||||
|
m_state[0] = seed;
|
||||||
|
for (unsigned int i = 1; i < N+1; i++)
|
||||||
|
m_state[i] = word32(F * (m_state[i-1] ^ (m_state[i-1] >> 30)) + i);
|
||||||
|
}
|
||||||
|
|
||||||
//! \brief Returns the next 32-bit word from the state array
|
//! \brief Returns the next 32-bit word from the state array
|
||||||
//! \returns the next 32-bit word from the state array
|
//! \returns the next 32-bit word from the state array
|
||||||
//! \details fetches the next word frm the state array, performs bit operations on
|
//! \details fetches the next word frm the state array, performs bit operations on
|
||||||
|
|
@ -148,7 +164,7 @@ protected:
|
||||||
//! \brief Performs the twist operaton on the state array
|
//! \brief Performs the twist operaton on the state array
|
||||||
void Twist()
|
void Twist()
|
||||||
{
|
{
|
||||||
static const unsigned long magic[2]={0x0UL, K};
|
static const word32 magic[2]={0x0UL, K};
|
||||||
word32 kk, temp;
|
word32 kk, temp;
|
||||||
|
|
||||||
CRYPTOPP_ASSERT(N >= M);
|
CRYPTOPP_ASSERT(N >= M);
|
||||||
|
|
@ -171,7 +187,7 @@ protected:
|
||||||
m_idx = 0;
|
m_idx = 0;
|
||||||
|
|
||||||
// Wipe temp
|
// Wipe temp
|
||||||
*((volatile word32*)&temp) = 0;
|
SecureWipeArray(&temp, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -179,9 +195,9 @@ private:
|
||||||
//! \brief 32-bit word state array of size N
|
//! \brief 32-bit word state array of size N
|
||||||
FixedSizeSecBlock<word32, N+1> m_state;
|
FixedSizeSecBlock<word32, N+1> m_state;
|
||||||
//! \brief the value used to seed the generator
|
//! \brief the value used to seed the generator
|
||||||
unsigned int m_seed;
|
word32 m_seed;
|
||||||
//! \brief the current index into the state array
|
//! \brief the current index into the state array
|
||||||
unsigned int m_idx;
|
word32 m_idx;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! \class MT19937
|
//! \class MT19937
|
||||||
|
|
|
||||||
|
|
@ -98,11 +98,6 @@ bool TestZinflate()
|
||||||
return !fail;
|
return !fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TestMersenne()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TestDefaultEncryptor()
|
bool TestDefaultEncryptor()
|
||||||
{
|
{
|
||||||
std::cout << "\nTesting DefaultEncryptor...\n\n";
|
std::cout << "\nTesting DefaultEncryptor...\n\n";
|
||||||
|
|
|
||||||
106
validat1.cpp
106
validat1.cpp
|
|
@ -45,6 +45,7 @@
|
||||||
#include "osrng.h"
|
#include "osrng.h"
|
||||||
#include "drbg.h"
|
#include "drbg.h"
|
||||||
#include "rdrand.h"
|
#include "rdrand.h"
|
||||||
|
#include "mersenne.h"
|
||||||
#include "zdeflate.h"
|
#include "zdeflate.h"
|
||||||
#include "smartptr.h"
|
#include "smartptr.h"
|
||||||
#include "channels.h"
|
#include "channels.h"
|
||||||
|
|
@ -72,7 +73,9 @@ bool ValidateAll(bool thorough)
|
||||||
pass=TestAutoSeeded() && pass;
|
pass=TestAutoSeeded() && pass;
|
||||||
pass=TestAutoSeededX917() && pass;
|
pass=TestAutoSeededX917() && pass;
|
||||||
// pass=TestSecRandom() && pass;
|
// pass=TestSecRandom() && pass;
|
||||||
|
#if (defined(CRYPTOPP_DEBUG) || defined(CRYPTOPP_COVERAGE)) && !defined(CRYPTOPP_IMPORTS)
|
||||||
|
pass=TestMersenne() && pass;
|
||||||
|
#endif
|
||||||
#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
|
#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
|
||||||
pass=TestRDRAND() && pass;
|
pass=TestRDRAND() && pass;
|
||||||
pass=TestRDSEED() && pass;
|
pass=TestRDSEED() && pass;
|
||||||
|
|
@ -96,7 +99,6 @@ bool ValidateAll(bool thorough)
|
||||||
// Additional tests due to no coverage
|
// Additional tests due to no coverage
|
||||||
pass=TestGzip() && pass;
|
pass=TestGzip() && pass;
|
||||||
pass=TestZinflate() && pass;
|
pass=TestZinflate() && pass;
|
||||||
pass=TestMersenne() && pass;
|
|
||||||
pass=TestDefaultEncryptor() && pass;
|
pass=TestDefaultEncryptor() && pass;
|
||||||
pass=TestDefaultEncryptorWithMAC() && pass;
|
pass=TestDefaultEncryptorWithMAC() && pass;
|
||||||
pass=TestLegacyEncryptor() && pass;
|
pass=TestLegacyEncryptor() && pass;
|
||||||
|
|
@ -449,7 +451,7 @@ bool TestOS_RNG()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
std::cout << "passed:";
|
std::cout << "passed:";
|
||||||
std::cout << " " << total << " generated bytes compressed to " << meter.GetTotalBytes() << " bytes by DEFLATE" << std::endl;
|
std::cout << " " << total << " generated bytes compressed to " << meter.GetTotalBytes() << " bytes by DEFLATE\n";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
std::cout << "\nNo operating system provided blocking random number generator, skipping test." << std::endl;
|
std::cout << "\nNo operating system provided blocking random number generator, skipping test." << std::endl;
|
||||||
|
|
@ -474,7 +476,7 @@ bool TestOS_RNG()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
std::cout << "passed:";
|
std::cout << "passed:";
|
||||||
std::cout << " 100000 generated bytes compressed to " << meter.GetTotalBytes() << " bytes by DEFLATE" << std::endl;
|
std::cout << " 100000 generated bytes compressed to " << meter.GetTotalBytes() << " bytes by DEFLATE\n";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
std::cout << "\nNo operating system provided nonblocking random number generator, skipping test." << std::endl;
|
std::cout << "\nNo operating system provided nonblocking random number generator, skipping test." << std::endl;
|
||||||
|
|
@ -511,7 +513,7 @@ bool TestAutoSeeded()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
std::cout << "passed:";
|
std::cout << "passed:";
|
||||||
std::cout << " 100000 generated bytes compressed to " << meter.GetTotalBytes() << " bytes by DEFLATE" << std::endl;
|
std::cout << " 100000 generated bytes compressed to " << meter.GetTotalBytes() << " bytes by DEFLATE\n";
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -575,7 +577,7 @@ bool TestAutoSeededX917()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
std::cout << "passed:";
|
std::cout << "passed:";
|
||||||
std::cout << " 100000 generated bytes compressed to " << meter.GetTotalBytes() << " bytes by DEFLATE" << std::endl;
|
std::cout << " 100000 generated bytes compressed to " << meter.GetTotalBytes() << " bytes by DEFLATE\n";
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -621,6 +623,90 @@ bool TestAutoSeededX917()
|
||||||
}
|
}
|
||||||
#endif // NO_OS_DEPENDENCE
|
#endif // NO_OS_DEPENDENCE
|
||||||
|
|
||||||
|
#if (defined(CRYPTOPP_DEBUG) || defined(CRYPTOPP_COVERAGE)) && !defined(CRYPTOPP_IMPORTS)
|
||||||
|
bool TestMersenne()
|
||||||
|
{
|
||||||
|
std::cout << "\nTesting Mersenne Twister...\n\n";
|
||||||
|
|
||||||
|
static const unsigned int ENTROPY_SIZE = 32;
|
||||||
|
bool equal = true, generate = true, discard = true, incorporate = false;
|
||||||
|
|
||||||
|
// First 10; http://create.stephan-brumme.com/mersenne-twister/
|
||||||
|
word32 result[10], expected[10] = {0xD091BB5C, 0x22AE9EF6,
|
||||||
|
0xE7E1FAEE, 0xD5C31F79, 0x2082352C, 0xF807B7DF, 0xE9D30005,
|
||||||
|
0x3895AFE1, 0xA1E24BBA, 0x4EE4092B};
|
||||||
|
|
||||||
|
MT19937ar prng;
|
||||||
|
prng.GenerateBlock(reinterpret_cast<byte*>(result), sizeof(result));
|
||||||
|
equal = (0 == ::memcmp(result, expected, sizeof(expected)));
|
||||||
|
|
||||||
|
if (equal)
|
||||||
|
{
|
||||||
|
std::cout << "passed:";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << "FAILED:";
|
||||||
|
equal = false;
|
||||||
|
}
|
||||||
|
std::cout << " Expected sequence from MT19937ar (2002 version)\n";
|
||||||
|
|
||||||
|
MeterFilter meter(new Redirector(TheBitBucket()));
|
||||||
|
RandomNumberSource test(prng, 100000, true, new Deflator(new Redirector(meter)));
|
||||||
|
|
||||||
|
if (meter.GetTotalBytes() < 100000)
|
||||||
|
{
|
||||||
|
std::cout << "FAILED:";
|
||||||
|
generate = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
std::cout << "passed:";
|
||||||
|
std::cout << " 100000 generated bytes compressed to " << meter.GetTotalBytes() << " bytes by DEFLATE\n";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
prng.DiscardBytes(100000);
|
||||||
|
}
|
||||||
|
catch(const Exception&)
|
||||||
|
{
|
||||||
|
discard = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!discard)
|
||||||
|
std::cout << "FAILED:";
|
||||||
|
else
|
||||||
|
std::cout << "passed:";
|
||||||
|
std::cout << " discarded 10000 bytes\n";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(prng.CanIncorporateEntropy())
|
||||||
|
{
|
||||||
|
SecByteBlock entropy(ENTROPY_SIZE);
|
||||||
|
OS_GenerateRandomBlock(false, entropy, entropy.SizeInBytes());
|
||||||
|
|
||||||
|
prng.IncorporateEntropy(entropy, entropy.SizeInBytes());
|
||||||
|
prng.IncorporateEntropy(entropy, entropy.SizeInBytes());
|
||||||
|
prng.IncorporateEntropy(entropy, entropy.SizeInBytes());
|
||||||
|
prng.IncorporateEntropy(entropy, entropy.SizeInBytes());
|
||||||
|
|
||||||
|
incorporate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(const Exception& /*ex*/)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!incorporate)
|
||||||
|
std::cout << "FAILED:";
|
||||||
|
else
|
||||||
|
std::cout << "passed:";
|
||||||
|
std::cout << " IncorporateEntropy with " << 4*ENTROPY_SIZE << " bytes" << std::endl;
|
||||||
|
|
||||||
|
return equal && generate && discard && incorporate;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
|
#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
|
||||||
bool TestRDRAND()
|
bool TestRDRAND()
|
||||||
{
|
{
|
||||||
|
|
@ -657,7 +743,7 @@ bool TestRDRAND()
|
||||||
// Coverity finding, also see http://stackoverflow.com/a/34509163/608639.
|
// Coverity finding, also see http://stackoverflow.com/a/34509163/608639.
|
||||||
StreamState ss(std::cout);
|
StreamState ss(std::cout);
|
||||||
std::cout << std::setiosflags(std::ios::fixed) << std::setprecision(6);
|
std::cout << std::setiosflags(std::ios::fixed) << std::setprecision(6);
|
||||||
std::cout << " Maurer Randomness Test returned value " << mv << std::endl;
|
std::cout << " Maurer Randomness Test returned value " << mv << "\n";
|
||||||
|
|
||||||
if (meter.GetTotalBytes() < SIZE)
|
if (meter.GetTotalBytes() < SIZE)
|
||||||
{
|
{
|
||||||
|
|
@ -691,9 +777,6 @@ bool TestRDRAND()
|
||||||
(void)rdrand.CanIncorporateEntropy();
|
(void)rdrand.CanIncorporateEntropy();
|
||||||
rdrand.IncorporateEntropy(NULLPTR, 0);
|
rdrand.IncorporateEntropy(NULLPTR, 0);
|
||||||
|
|
||||||
if (!(entropy && compress && discard))
|
|
||||||
std::cout.flush();
|
|
||||||
|
|
||||||
return entropy && compress && discard;
|
return entropy && compress && discard;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -769,9 +852,6 @@ bool TestRDSEED()
|
||||||
(void)rdseed.CanIncorporateEntropy();
|
(void)rdseed.CanIncorporateEntropy();
|
||||||
rdseed.IncorporateEntropy(NULLPTR, 0);
|
rdseed.IncorporateEntropy(NULLPTR, 0);
|
||||||
|
|
||||||
if (!(entropy && compress && discard))
|
|
||||||
std::cout.flush();
|
|
||||||
|
|
||||||
return entropy && compress && discard;
|
return entropy && compress && discard;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue