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