rpm/beecrypt/mtprng.c

244 lines
5.4 KiB
C

/**
* \file mtprng.c
*
* Mersenne Twister pseudo-random number generator, code.
*
* Developed by Makoto Matsumoto and Takuji Nishimura
*
* For more information, see:
* http://www.math.keio.ac.jp/~matumoto/emt.html
*
* Adapted from optimized code by Shawn J. Cokus <cokus@math.washington.edu>
*
* Note: this generator has a very long period, passes statistical test, but
* needs more study to determine whether it is cryptographically strong enough.
*
*/
/* Copyright (c) 1998, 1999, 2000, 2001 Virtual Unlimited B.V.
*
* Author: Bob Deblier <bob@virtualunlimited.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "system.h"
#include "beecrypt.h"
#include "mtprng.h"
#include "mp32opt.h"
#include "mp32.h"
#include "debug.h"
#define hiBit(a) ((a) & 0x80000000)
#define loBit(a) ((a) & 0x1)
#define loBits(a) ((a) & 0x7FFFFFFF)
#define mixBits(a, b) (hiBit(a) | loBits(b))
/*@-sizeoftype@*/
const randomGenerator mtprng = { "Mersenne Twister", sizeof(mtprngParam), (randomGeneratorSetup) mtprngSetup, (randomGeneratorSeed) mtprngSeed, (randomGeneratorNext) mtprngNext, (randomGeneratorCleanup) mtprngCleanup };
/*@=sizeoftype@*/
/**
*/
/*@-boundsread@*/
static void mtprngReload(mtprngParam* mp)
/*@modifies mp @*/
{
register uint32* p0 = mp->state;
register uint32* p2=p0+2, *pM = p0+M, s0, s1;
register int j;
for (s0=mp->state[0], s1=mp->state[1], j=N-M+1; --j; s0=s1, s1=*(p2++))
*(p0++) = *(pM++) ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0);
for (pM=mp->state, j=M; --j; s0=s1, s1=*(p2++))
*(p0++) = *(pM++) ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0);
s1 = mp->state[0], *p0 = *pM ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0);
mp->left = N;
mp->nextw = mp->state;
}
/*@=boundsread@*/
int mtprngSetup(mtprngParam* mp)
{
if (mp)
{
#ifdef _REENTRANT
# if WIN32
if (!(mp->lock = CreateMutex(NULL, FALSE, NULL)))
return -1;
# else
# if HAVE_THREAD_H && HAVE_SYNCH_H
if (mutex_init(&mp->lock, USYNC_THREAD, (void *) 0))
return -1;
# elif HAVE_PTHREAD_H
/*@-nullpass@*/
/*@-moduncon@*/
if (pthread_mutex_init(&mp->lock, (pthread_mutexattr_t *) 0))
return -1;
/*@=moduncon@*/
/*@=nullpass@*/
# endif
# endif
#endif
mp->left = 0;
return entropyGatherNext(mp->state, N+1);
}
return -1;
}
/*@-boundswrite@*/
int mtprngSeed(mtprngParam* mp, const uint32* data, int size)
{
if (mp)
{
int needed = N+1;
uint32* dest = mp->state;
#ifdef _REENTRANT
# if WIN32
if (WaitForSingleObject(mp->lock, INFINITE) != WAIT_OBJECT_0)
return -1;
# else
# if HAVE_THREAD_H && HAVE_SYNCH_H
if (mutex_lock(&mp->lock))
return -1;
# elif HAVE_PTHREAD_H
/*@-moduncon@*/
if (pthread_mutex_lock(&mp->lock))
return -1;
/*@=moduncon@*/
# endif
# endif
#endif
while (size < needed)
{
mp32copy(size, dest, data);
dest += size;
needed -= size;
}
mp32copy(needed, dest, data);
#ifdef _REENTRANT
# if WIN32
if (!ReleaseMutex(mp->lock))
return -1;
# else
# if HAVE_THREAD_H && HAVE_SYNCH_H
if (mutex_unlock(&mp->lock))
return -1;
# elif HAVE_PTHREAD_H
/*@-moduncon@*/
if (pthread_mutex_unlock(&mp->lock))
return -1;
/*@=moduncon@*/
# endif
# endif
#endif
return 0;
}
return -1;
}
/*@=boundswrite@*/
/*@-boundswrite@*/
int mtprngNext(mtprngParam* mp, uint32* data, int size)
{
if (mp)
{
register uint32 tmp;
#ifdef _REENTRANT
# if WIN32
if (WaitForSingleObject(mp->lock, INFINITE) != WAIT_OBJECT_0)
return -1;
# else
# if HAVE_THREAD_H && HAVE_SYNCH_H
if (mutex_lock(&mp->lock))
return -1;
# elif HAVE_PTHREAD_H
/*@-moduncon@*/
if (pthread_mutex_lock(&mp->lock))
return -1;
/*@=moduncon@*/
# endif
# endif
#endif
/*@-branchstate@*/
while (size--)
{
if (mp->left == 0)
mtprngReload(mp);
tmp = *(mp->nextw++);
tmp ^= (tmp >> 11);
tmp ^= (tmp << 7) & 0x9D2C5680;
tmp ^= (tmp << 15) & 0xEFC60000;
tmp ^= (tmp >> 18);
mp->left--;
*(data++) = tmp;
}
/*@=branchstate@*/
#ifdef _REENTRANT
# if WIN32
if (!ReleaseMutex(mp->lock))
return -1;
# else
# if HAVE_THREAD_H && HAVE_SYNCH_H
if (mutex_unlock(&mp->lock))
return -1;
# elif HAVE_PTHREAD_H
/*@-moduncon@*/
if (pthread_mutex_unlock(&mp->lock))
return -1;
/*@=moduncon@*/
# endif
# endif
#endif
return 0;
}
return -1;
}
/*@=boundswrite@*/
int mtprngCleanup(mtprngParam* mp)
{
if (mp)
{
#ifdef _REENTRANT
# if WIN32
if (!CloseHandle(mp->lock))
return -1;
# else
# if HAVE_THREAD_H && HAVE_SYNCH_H
if (mutex_destroy(&mp->lock))
return -1;
# elif HAVE_PTHREAD_H
/*@-moduncon@*/
if (pthread_mutex_destroy(&mp->lock))
return -1;
/*@=moduncon@*/
# endif
# endif
#endif
return 0;
}
return -1;
}