- Main Page
- Namespaces
- Classes
- Files

# rng.cpp

    00001 // rng.cpp - written and placed in the public domain by Wei Dai
    00002
    00003 #include "pch.h"
    00004
    00005 #include "rng.h"
    00006 #include "fips140.h"
    00007
    00008 #include <time.h>
    00009 #include <math.h>
    00010
    00011 NAMESPACE_BEGIN(CryptoPP)
    00012
    00013 // linear congruential generator
    00014 // originally by William S. England
    00015
    00016 // do not use for cryptographic purposes
    00017
    00018 /*
    00019 ** Original_numbers are the original published m and q in the
    00020 ** ACM article above.  John Burton has furnished numbers for
    00021 ** a reportedly better generator.  The new numbers are now
    00022 ** used in this program by default.
    00023 */
    00024
    00025 #ifndef LCRNG_ORIGINAL_NUMBERS
    00026 const word32 LC_RNG::m=2147483647L;
    00027 const word32 LC_RNG::q=44488L;
    00028
    00029 const word16 LC_RNG::a=(unsigned int)48271L;
    00030 const word16 LC_RNG::r=3399;
    00031 #else
    00032 const word32 LC_RNG::m=2147483647L;
    00033 const word32 LC_RNG::q=127773L;
    00034
    00035 const word16 LC_RNG::a=16807;
    00036 const word16 LC_RNG::r=2836;
    00037 #endif
    00038
    00039 void LC_RNG::GenerateBlock(byte *output, size_t size)
    00040 {
    00041         while (size--)
    00042         {
    00043                 word32 hi = seed/q;
    00044                 word32 lo = seed%q;
    00045
    00046                 long test = a*lo - r*hi;
    00047
    00048                 if (test > 0)
    00049                         seed = test;
    00050                 else
    00051                         seed = test+ m;
    00052
    00053                 *output++ = (GETBYTE(seed, 0) ^ GETBYTE(seed, 1) ^ GETBYTE(seed, 2) ^ GETBYTE(seed, 3));
    00054         }
    00055 }
    00056
    00057 // ********************************************************
    00058
    00059 #ifndef CRYPTOPP_IMPORTS
    00060
    00061 X917RNG::X917RNG(BlockTransformation *c, const byte *seed, const byte *deterministicTimeVector)
    00062         : cipher(c),
    00063           S(cipher->BlockSize()),
    00064           dtbuf(S),
    00065           randseed(seed, S),
    00066           m_lastBlock(S),
    00067           m_deterministicTimeVector(deterministicTimeVector, deterministicTimeVector ? S : 0)
    00068 {
    00069         if (!deterministicTimeVector)
    00070         {
    00071                 time_t tstamp1 = time(0);
    00072                 xorbuf(dtbuf, (byte *)&tstamp1, UnsignedMin(sizeof(tstamp1), S));
    00073                 cipher->ProcessBlock(dtbuf);
    00074                 clock_t tstamp2 = clock();
    00075                 xorbuf(dtbuf, (byte *)&tstamp2, UnsignedMin(sizeof(tstamp2), S));
    00076                 cipher->ProcessBlock(dtbuf);
    00077         }
    00078
    00079         // for FIPS 140-2
    00080         GenerateBlock(m_lastBlock, S);
    00081 }
    00082
    00083 void X917RNG::GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size)
    00084 {
    00085         while (size > 0)
    00086         {
    00087                 // calculate new enciphered timestamp
    00088                 if (m_deterministicTimeVector.size())
    00089                 {
    00090                         cipher->ProcessBlock(m_deterministicTimeVector, dtbuf);
    00091                         IncrementCounterByOne(m_deterministicTimeVector, S);
    00092                 }
    00093                 else
    00094                 {
    00095                         clock_t c = clock();
    00096                         xorbuf(dtbuf, (byte *)&c, UnsignedMin(sizeof(c), S));
    00097                         time_t t = time(NULL);
    00098                         xorbuf(dtbuf+S-UnsignedMin(sizeof(t), S), (byte *)&t, UnsignedMin(sizeof(t), S));
    00099                         cipher->ProcessBlock(dtbuf);
    00100                 }
    00101
    00102                 // combine enciphered timestamp with seed
    00103                 xorbuf(randseed, dtbuf, S);
    00104
    00105                 // generate a new block of random bytes
    00106                 cipher->ProcessBlock(randseed);
    00107                 if (memcmp(m_lastBlock, randseed, S) == 0)
    00108                         throw SelfTestFailure("X917RNG: Continuous random number generator test failed.");
    00109
    00110                 // output random bytes
    00111                 size_t len = UnsignedMin(S, size);
    00112                 target.ChannelPut(channel, randseed, len);
    00113                 size -= len;
    00114
    00115                 // compute new seed vector
    00116                 memcpy(m_lastBlock, randseed, S);
    00117                 xorbuf(randseed, dtbuf, S);
    00118                 cipher->ProcessBlock(randseed);
    00119         }
    00120 }
    00121
    00122 #endif
    00123
    00124 MaurerRandomnessTest::MaurerRandomnessTest()
    00125         : sum(0.0), n(0)
    00126 {
    00127         for (unsigned i=0; i<V; i++)
    00128                 tab[i] = 0;
    00129 }
    00130
    00131 size_t MaurerRandomnessTest::Put2(const byte *inString, size_t length, int messageEnd, bool blocking)
    00132 {
    00133         while (length--)
    00134         {
    00135                 byte inByte = *inString++;
    00136                 if (n >= Q)
    00137                         sum += log(double(n - tab[inByte]));
    00138                 tab[inByte] = n;
    00139                 n++;
    00140         }
    00141         return 0;
    00142 }
    00143
    00144 double MaurerRandomnessTest::GetTestValue() const
    00145 {
    00146         if (BytesNeeded() > 0)
    00147                 throw Exception(Exception::OTHER_ERROR, "MaurerRandomnessTest: " + IntToString(BytesNeeded()) + " more bytes of input needed");
    00148
    00149         double fTu = (sum/(n-Q))/log(2.0);      // this is the test value defined by Maurer
    00150
    00151         double value = fTu * 0.1392;            // arbitrarily normalize it to
    00152         return value > 1.0 ? 1.0 : value;       // a number between 0 and 1
    00153 }
    00154
    00155 NAMESPACE_END