Line | Count | Source (jump to first uncovered line) |
1 | | /* Mersenne Twister pseudo-random number generator functions. |
2 | | |
3 | | Copyright 2002, 2003, 2013, 2014 Free Software Foundation, Inc. |
4 | | |
5 | | This file is part of the GNU MP Library. |
6 | | |
7 | | The GNU MP Library is free software; you can redistribute it and/or modify |
8 | | it under the terms of either: |
9 | | |
10 | | * the GNU Lesser General Public License as published by the Free |
11 | | Software Foundation; either version 3 of the License, or (at your |
12 | | option) any later version. |
13 | | |
14 | | or |
15 | | |
16 | | * the GNU General Public License as published by the Free Software |
17 | | Foundation; either version 2 of the License, or (at your option) any |
18 | | later version. |
19 | | |
20 | | or both in parallel, as here. |
21 | | |
22 | | The GNU MP Library is distributed in the hope that it will be useful, but |
23 | | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
24 | | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
25 | | for more details. |
26 | | |
27 | | You should have received copies of the GNU General Public License and the |
28 | | GNU Lesser General Public License along with the GNU MP Library. If not, |
29 | | see https://www.gnu.org/licenses/. */ |
30 | | |
31 | | #include "gmp-impl.h" |
32 | | #include "randmt.h" |
33 | | |
34 | | |
35 | | /* Calculate (b^e) mod (2^n-k) for e=1074888996, n=19937 and k=20023, |
36 | | needed by the seeding function below. */ |
37 | | static void |
38 | | mangle_seed (mpz_ptr r) |
39 | 0 | { |
40 | 0 | mpz_t t, b; |
41 | 0 | unsigned long e = 0x40118124; |
42 | 0 | unsigned long bit = 0x20000000; |
43 | |
|
44 | 0 | mpz_init2 (t, 19937L); |
45 | 0 | mpz_init_set (b, r); |
46 | |
|
47 | 0 | do |
48 | 0 | { |
49 | 0 | mpz_mul (r, r, r); |
50 | |
|
51 | 0 | reduce: |
52 | 0 | for (;;) |
53 | 0 | { |
54 | 0 | mpz_tdiv_q_2exp (t, r, 19937L); |
55 | 0 | if (SIZ (t) == 0) |
56 | 0 | break; |
57 | 0 | mpz_tdiv_r_2exp (r, r, 19937L); |
58 | 0 | mpz_addmul_ui (r, t, 20023L); |
59 | 0 | } |
60 | |
|
61 | 0 | if ((e & bit) != 0) |
62 | 0 | { |
63 | 0 | e ^= bit; |
64 | 0 | mpz_mul (r, r, b); |
65 | 0 | goto reduce; |
66 | 0 | } |
67 | | |
68 | 0 | bit >>= 1; |
69 | 0 | } |
70 | 0 | while (bit != 0); |
71 | | |
72 | 0 | mpz_clear (t); |
73 | 0 | mpz_clear (b); |
74 | 0 | } |
75 | | |
76 | | |
77 | | /* Seeding function. Uses powering modulo a non-Mersenne prime to obtain |
78 | | a permutation of the input seed space. The modulus is 2^19937-20023, |
79 | | which is probably prime. The power is 1074888996. In order to avoid |
80 | | seeds 0 and 1 generating invalid or strange output, the input seed is |
81 | | first manipulated as follows: |
82 | | |
83 | | seed1 = seed mod (2^19937-20027) + 2 |
84 | | |
85 | | so that seed1 lies between 2 and 2^19937-20026 inclusive. Then the |
86 | | powering is performed as follows: |
87 | | |
88 | | seed2 = (seed1^1074888996) mod (2^19937-20023) |
89 | | |
90 | | and then seed2 is used to bootstrap the buffer. |
91 | | |
92 | | This method aims to give guarantees that: |
93 | | a) seed2 will never be zero, |
94 | | b) seed2 will very seldom have a very low population of ones in its |
95 | | binary representation, and |
96 | | c) every seed between 0 and 2^19937-20028 (inclusive) will yield a |
97 | | different sequence. |
98 | | |
99 | | CAVEATS: |
100 | | |
101 | | The period of the seeding function is 2^19937-20027. This means that |
102 | | with seeds 2^19937-20027, 2^19937-20026, ... the exact same sequences |
103 | | are obtained as with seeds 0, 1, etc.; it also means that seed -1 |
104 | | produces the same sequence as seed 2^19937-20028, etc. |
105 | | |
106 | | Moreover, c) is not guaranted, there are many seeds yielding to the |
107 | | same sequence, because gcd (1074888996, 2^19937 - 20023 - 1) = 12. |
108 | | E.g. x and x'=x*19^((2^19937-20023-1) / 12) mod (2^19937-20023), if |
109 | | chosen as seed1, generate the same seed2, for every x. |
110 | | Similarly x" can be obtained from x', obtaining 12 different |
111 | | values. |
112 | | */ |
113 | | |
114 | | static void |
115 | | randseed_mt (gmp_randstate_ptr rstate, mpz_srcptr seed) |
116 | 0 | { |
117 | 0 | int i; |
118 | 0 | size_t cnt; |
119 | |
|
120 | 0 | gmp_rand_mt_struct *p; |
121 | 0 | mpz_t mod; /* Modulus. */ |
122 | 0 | mpz_t seed1; /* Intermediate result. */ |
123 | |
|
124 | 0 | p = (gmp_rand_mt_struct *) RNG_STATE (rstate); |
125 | |
|
126 | 0 | mpz_init2 (mod, 19938L); |
127 | 0 | mpz_init2 (seed1, 19937L); |
128 | |
|
129 | 0 | mpz_setbit (mod, 19937L); |
130 | 0 | mpz_sub_ui (mod, mod, 20027L); |
131 | 0 | mpz_mod (seed1, seed, mod); /* Reduce `seed' modulo `mod'. */ |
132 | 0 | mpz_clear (mod); |
133 | 0 | mpz_add_ui (seed1, seed1, 2L); /* seed1 is now ready. */ |
134 | 0 | mangle_seed (seed1); /* Perform the mangling by powering. */ |
135 | | |
136 | | /* Copy the last bit into bit 31 of mt[0] and clear it. */ |
137 | 0 | p->mt[0] = (mpz_tstbit (seed1, 19936L) != 0) ? 0x80000000 : 0; |
138 | 0 | mpz_clrbit (seed1, 19936L); |
139 | | |
140 | | /* Split seed1 into N-1 32-bit chunks. */ |
141 | 0 | mpz_export (&p->mt[1], &cnt, -1, sizeof (p->mt[1]), 0, |
142 | 0 | 8 * sizeof (p->mt[1]) - 32, seed1); |
143 | 0 | mpz_clear (seed1); |
144 | 0 | cnt++; |
145 | 0 | ASSERT (cnt <= N); |
146 | 0 | while (cnt < N) |
147 | 0 | p->mt[cnt++] = 0; |
148 | | |
149 | | /* Warm the generator up if necessary. */ |
150 | 0 | if (WARM_UP != 0) |
151 | 0 | for (i = 0; i < WARM_UP / N; i++) |
152 | 0 | __gmp_mt_recalc_buffer (p->mt); |
153 | |
|
154 | 0 | p->mti = WARM_UP % N; |
155 | 0 | } |
156 | | |
157 | | |
158 | | static const gmp_randfnptr_t Mersenne_Twister_Generator = { |
159 | | randseed_mt, |
160 | | __gmp_randget_mt, |
161 | | __gmp_randclear_mt, |
162 | | __gmp_randiset_mt |
163 | | }; |
164 | | |
165 | | /* Initialize MT-specific data. */ |
166 | | void |
167 | | gmp_randinit_mt (gmp_randstate_ptr rstate) |
168 | 0 | { |
169 | 0 | __gmp_randinit_mt_noseed (rstate); |
170 | 0 | RNG_FNPTR (rstate) = (void *) &Mersenne_Twister_Generator; |
171 | 0 | } |