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
|
// rng.cpp - written and placed in the public domain by Wei Dai
#include "pch.h"
#include "rng.h"
#include "fips140.h"
#include <math.h>
NAMESPACE_BEGIN(CryptoPP)
// linear congruential generator
// originally by William S. England
// do not use for cryptographic purposes
/*
** Original_numbers are the original published m and q in the
** ACM article above. John Burton has furnished numbers for
** a reportedly better generator. The new numbers are now
** used in this program by default.
*/
#ifndef LCRNG_ORIGINAL_NUMBERS
const word32 LC_RNG::m=2147483647L;
const word32 LC_RNG::q=44488L;
const word16 LC_RNG::a=(unsigned int)48271L;
const word16 LC_RNG::r=3399;
#else
const word32 LC_RNG::m=2147483647L;
const word32 LC_RNG::q=127773L;
const word16 LC_RNG::a=16807;
const word16 LC_RNG::r=2836;
#endif
void LC_RNG::GenerateBlock(byte *output, size_t size)
{
while (size--)
{
word32 hi = seed/q;
word32 lo = seed%q;
long test = a*lo - r*hi;
if (test > 0)
seed = test;
else
seed = test+ m;
*output++ = (GETBYTE(seed, 0) ^ GETBYTE(seed, 1) ^ GETBYTE(seed, 2) ^ GETBYTE(seed, 3));
}
}
// ********************************************************
#ifndef CRYPTOPP_IMPORTS
X917RNG::X917RNG(BlockTransformation *c, const byte *seed, const byte *deterministicTimeVector)
: cipher(c),
S(cipher->BlockSize()),
dtbuf(S),
randseed(seed, S),
m_lastBlock(S),
m_deterministicTimeVector(deterministicTimeVector, deterministicTimeVector ? S : 0)
{
assert (deterministicTimeVector);
// for FIPS 140-2
GenerateBlock(m_lastBlock, S);
}
void X917RNG::GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size)
{
while (size > 0)
{
// calculate new enciphered timestamp
if (m_deterministicTimeVector.size())
{
cipher->ProcessBlock(m_deterministicTimeVector, dtbuf);
IncrementCounterByOne(m_deterministicTimeVector, S);
}
else
{
assert(false);
}
// combine enciphered timestamp with seed
xorbuf(randseed, dtbuf, S);
// generate a new block of random bytes
cipher->ProcessBlock(randseed);
if (memcmp(m_lastBlock, randseed, S) == 0)
throw SelfTestFailure("X917RNG: Continuous random number generator test failed.");
// output random bytes
size_t len = UnsignedMin(S, size);
target.ChannelPut(channel, randseed, len);
size -= len;
// compute new seed vector
memcpy(m_lastBlock, randseed, S);
xorbuf(randseed, dtbuf, S);
cipher->ProcessBlock(randseed);
}
}
#endif
MaurerRandomnessTest::MaurerRandomnessTest()
: sum(0.0), n(0)
{
for (unsigned i=0; i<V; i++)
tab[i] = 0;
}
size_t MaurerRandomnessTest::Put2(const byte *inString, size_t length, int messageEnd, bool blocking)
{
while (length--)
{
byte inByte = *inString++;
if (n >= Q)
sum += log(double(n - tab[inByte]));
tab[inByte] = n;
n++;
}
return 0;
}
double MaurerRandomnessTest::GetTestValue() const
{
if (BytesNeeded() > 0)
throw Exception(Exception::OTHER_ERROR, "MaurerRandomnessTest: " + IntToString(BytesNeeded()) + " more bytes of input needed");
double fTu = (sum/(n-Q))/log(2.0); // this is the test value defined by Maurer
double value = fTu * 0.1392; // arbitrarily normalize it to
return value > 1.0 ? 1.0 : value; // a number between 0 and 1
}
NAMESPACE_END
|