1 /*
2  * Copyright (c) 1998, 1999, 2000, 2001 X-Way Rights BV
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  */
19 
20 /*!\mtprng.c
21  * \brief Mersenne Twister pseudo-random number generator.
22  *
23  * Developed by Makoto Matsumoto and Takuji Nishimura. For more information,
24  * see: http://www.math.keio.ac.jp/~matumoto/emt.html
25  *
26  * Adapted from optimized code by Shawn J. Cokus <cokus@math.washington.edu>
27  *
28  * \warning This generator has a very long period, passes statistical test and
29  *          is very fast, but is not recommended for use in cryptography.
30  *
31  * \author Bob Deblier <bob.deblier@telenet.be>
32  * \ingroup PRNG_m
33  */
34 
35 #define BEECRYPT_DLL_EXPORT
36 
37 #if HAVE_CONFIG_H
38 # include "config.h"
39 #endif
40 
41 #include "beecrypt/mtprng.h"
42 
43 #define hiBit(a)		((a) & 0x80000000U)
44 #define loBit(a)		((a) & 0x1U)
45 #define loBits(a)		((a) & 0x7FFFFFFFU)
46 #define mixBits(a, b)	(hiBit(a) | loBits(b))
47 
48 const randomGenerator mtprng = { "Mersenne Twister", sizeof(mtprngParam), (randomGeneratorSetup) mtprngSetup, (randomGeneratorSeed) mtprngSeed, (randomGeneratorNext) mtprngNext, (randomGeneratorCleanup) mtprngCleanup };
49 
mtprngReload(mtprngParam * mp)50 static void mtprngReload(mtprngParam* mp)
51 {
52     register uint32_t *p0 = mp->state;
53 	register uint32_t *p2 = p0+2, *pM = p0+M, s0, s1;
54     register int j;
55 
56     for (s0=mp->state[0], s1=mp->state[1], j=N-M+1; --j; s0=s1, s1=*(p2++))
57         *(p0++) = *(pM++) ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0);
58 
59     for (pM=mp->state, j=M; --j; s0=s1, s1=*(p2++))
60         *(p0++) = *(pM++) ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0);
61 
62     s1 = mp->state[0], *p0 = *pM ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0);
63 
64     mp->left = N;
65     mp->nextw = mp->state;
66 }
67 
mtprngSetup(mtprngParam * mp)68 int mtprngSetup(mtprngParam* mp)
69 {
70 	if (mp)
71 	{
72 		#ifdef _REENTRANT
73 		# if WIN32
74 		if (!(mp->lock = CreateMutex(NULL, FALSE, NULL)))
75 			return -1;
76 		# else
77 		#  if HAVE_THREAD_H && HAVE_SYNCH_H
78 		if (mutex_init(&mp->lock, USYNC_THREAD, (void *) 0))
79 			return -1;
80 		#  elif HAVE_PTHREAD_H
81 		if (pthread_mutex_init(&mp->lock, (pthread_mutexattr_t *) 0))
82 			return -1;
83 		#  endif
84 		# endif
85 		#endif
86 
87 		mp->left = 0;
88 
89 		return entropyGatherNext((byte*) mp->state, (N+1) * sizeof(uint32_t));
90 	}
91 	return -1;
92 }
93 
mtprngSeed(mtprngParam * mp,const byte * data,size_t size)94 int mtprngSeed(mtprngParam* mp, const byte* data, size_t size)
95 {
96 	if (mp)
97 	{
98 		size_t	needed = (N+1) * sizeof(uint32_t);
99 		byte*	dest = (byte*) mp->state;
100 
101 		#ifdef _REENTRANT
102 		# if WIN32
103 		if (WaitForSingleObject(mp->lock, INFINITE) != WAIT_OBJECT_0)
104 			return -1;
105 		# else
106 		#  if HAVE_THREAD_H && HAVE_SYNCH_H
107 		if (mutex_lock(&mp->lock))
108 			return -1;
109 		#  elif HAVE_PTHREAD_H
110 		if (pthread_mutex_lock(&mp->lock))
111 			return -1;
112 		#  endif
113 		# endif
114 		#endif
115 		while (size < needed)
116 		{
117 			memcpy(dest, data, size);
118 			dest += size;
119 			needed -= size;
120 		}
121 		memcpy(dest, data, needed);
122 		#ifdef _REENTRANT
123 		# if WIN32
124 		if (!ReleaseMutex(mp->lock))
125 			return -1;
126 		# else
127 		#  if HAVE_THREAD_H && HAVE_SYNCH_H
128 		if (mutex_unlock(&mp->lock))
129 			return -1;
130 		#  elif HAVE_PTHREAD_H
131 		if (pthread_mutex_unlock(&mp->lock))
132 			return -1;
133 		#  endif
134 		# endif
135 		#endif
136 		return 0;
137 	}
138 	return -1;
139 }
140 
mtprngNext(mtprngParam * mp,byte * data,size_t size)141 int mtprngNext(mtprngParam* mp, byte* data, size_t size)
142 {
143 	if (mp)
144 	{
145 		uint32_t tmp;
146 
147 		#ifdef _REENTRANT
148 		# if WIN32
149 		if (WaitForSingleObject(mp->lock, INFINITE) != WAIT_OBJECT_0)
150 			return -1;
151 		# else
152 		#  if HAVE_THREAD_H && HAVE_SYNCH_H
153 		if (mutex_lock(&mp->lock))
154 			return -1;
155 		#  elif HAVE_PTHREAD_H
156 		if (pthread_mutex_lock(&mp->lock))
157 			return -1;
158 		#  endif
159 		# endif
160 		#endif
161 		while (size > 0)
162 		{
163 			if (mp->left == 0)
164 				mtprngReload(mp);
165 
166 			tmp = *(mp->nextw++);
167 			tmp ^= (tmp >> 11);
168 			tmp ^= (tmp << 7) & 0x9D2C5680U;
169 			tmp ^= (tmp << 15) & 0xEFC60000U;
170 			tmp ^= (tmp >> 18);
171 			mp->left--;
172 
173 			if (size >= 4)
174 			{
175 				memcpy(data, &tmp, 4);
176 				size -= 4;
177 			}
178 			else
179 			{
180 				memcpy(data, &tmp, size);
181 				size = 0;
182 			}
183 		}
184 		#ifdef _REENTRANT
185 		# if WIN32
186 		if (!ReleaseMutex(mp->lock))
187 			return -1;
188 		# else
189 		#  if HAVE_THREAD_H && HAVE_SYNCH_H
190 		if (mutex_unlock(&mp->lock))
191 			return -1;
192 		#  elif HAVE_PTHREAD_H
193 		if (pthread_mutex_unlock(&mp->lock))
194 			return -1;
195 		#  endif
196 		# endif
197 		#endif
198 		return 0;
199 	}
200 	return -1;
201 }
202 
mtprngCleanup(mtprngParam * mp)203 int mtprngCleanup(mtprngParam* mp)
204 {
205 	if (mp)
206 	{
207 		#ifdef _REENTRANT
208 		# if WIN32
209 		if (!CloseHandle(mp->lock))
210 			return -1;
211 		# else
212 		#  if HAVE_THREAD_H && HAVE_SYNCH_H
213 		if (mutex_destroy(&mp->lock))
214 			return -1;
215 		#  elif HAVE_PTHREAD_H
216 		if (pthread_mutex_destroy(&mp->lock))
217 			return -1;
218 		#  endif
219 		# endif
220 		#endif
221 		return 0;
222 	}
223 	return -1;
224 }
225