1 /* $NetBSD: mertwist.c,v 1.7 2008/02/17 22:49:11 matt Exp $ */
3 * Copyright (c) 2008 The NetBSD Foundation, Inc.
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Matt Thomas <matt@3am-software.com>.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
31 #if defined(_KERNEL) || defined(_STANDALONE)
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/systm.h>
36 #include <lib/libkern/libkern.h>
42 #define KASSERT(x) assert(x)
46 * Mersenne Twister. Produces identical output compared to mt19937ar.c
47 * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
50 #define MATRIX_A(a) (((a) & 1) ? 0x9908b0df : 0)
51 #define TEMPERING_MASK_B 0x9d2c5680
52 #define TEMPERING_MASK_C 0xefc60000
53 #define UPPER_MASK 0x80000000
54 #define LOWER_MASK 0x7fffffff
55 #define MIX(u,l) (((u) & UPPER_MASK) | ((l) & LOWER_MASK))
57 #define KNUTH_MULTIPLIER 0x6c078965
60 #define MTPRNG_RLEN 624
62 #define MTPRNG_POS1 397
64 static void mtprng_refresh(struct mtprng_state
*);
67 * Initialize the generator from a seed
70 mtprng_init32(struct mtprng_state
*mt
, uint32_t seed
)
75 * Use Knuth's algorithm for expanding this seed over its
76 * portion of the key space.
78 mt
->mt_elem
[0] = seed
;
79 for (i
= 1; i
< MTPRNG_RLEN
; i
++) {
80 mt
->mt_elem
[i
] = KNUTH_MULTIPLIER
81 * (mt
->mt_elem
[i
-1] ^ (mt
->mt_elem
[i
-1] >> 30)) + i
;
88 mtprng_initarray(struct mtprng_state
*mt
, const uint32_t *key
, size_t keylen
)
94 * Use Knuth's algorithm for expanding this seed over its
95 * portion of the key space.
97 mt
->mt_elem
[0] = 19650218UL;
98 for (i
= 1; i
< MTPRNG_RLEN
; i
++) {
99 mt
->mt_elem
[i
] = KNUTH_MULTIPLIER
100 * (mt
->mt_elem
[i
-1] ^ (mt
->mt_elem
[i
-1] >> 30)) + i
;
107 k
= (keylen
< MTPRNG_RLEN
? MTPRNG_RLEN
: keylen
);
109 mp
= &mt
->mt_elem
[1];
110 for (; k
-- > 0; mp
++) {
111 mp
[0] ^= (mp
[-1] ^ (mp
[-1] >> 30)) * 1664525UL;
113 if (++i
== MTPRNG_RLEN
) {
114 KASSERT(mp
== mt
->mt_elem
+ MTPRNG_RLEN
- 1);
115 mt
->mt_elem
[0] = mp
[0];
122 for (j
= MTPRNG_RLEN
; --j
> 0; mp
++) {
123 mp
[0] ^= (mp
[-1] ^ (mp
[-1] >> 30)) * 1566083941UL;
125 if (++i
== MTPRNG_RLEN
) {
126 KASSERT(mp
== mt
->mt_elem
+ MTPRNG_RLEN
- 1);
127 mt
->mt_elem
[0] = mp
[0];
132 mt
->mt_elem
[0] = 0x80000000;
137 * Generate an array of 624 untempered numbers
140 mtprng_refresh(struct mtprng_state
*mt
)
145 * The following has been refactored to avoid the need for 'mod 624'
147 for (i
= 0, j
= MTPRNG_POS1
; j
< MTPRNG_RLEN
; i
++, j
++) {
148 y
= MIX(mt
->mt_elem
[i
], mt
->mt_elem
[i
+1]);
149 mt
->mt_elem
[i
] = mt
->mt_elem
[j
] ^ (y
>> 1) ^ MATRIX_A(y
);
151 for (j
= 0; i
< MTPRNG_RLEN
- 1; i
++, j
++) {
152 y
= MIX(mt
->mt_elem
[i
], mt
->mt_elem
[i
+1]);
153 mt
->mt_elem
[i
] = mt
->mt_elem
[j
] ^ (y
>> 1) ^ MATRIX_A(y
);
155 y
= MIX(mt
->mt_elem
[MTPRNG_RLEN
- 1], mt
->mt_elem
[0]);
156 mt
->mt_elem
[MTPRNG_RLEN
- 1] =
157 mt
->mt_elem
[MTPRNG_POS1
- 1] ^ (y
>> 1) ^ MATRIX_A(y
);
161 * Extract a tempered PRN based on the current index. Then recompute a
162 * new value for the index. This avoids having to regenerate the array
163 * every 624 iterations. We can do this since recomputing only the next
164 * element and the [(i + 397) % 624] one.
167 mtprng_rawrandom(struct mtprng_state
*mt
)
170 const size_t i
= mt
->mt_idx
;
174 * First generate the random value for the current position.
178 x
^= (x
<< 7) & TEMPERING_MASK_B
;
179 x
^= (x
<< 15) & TEMPERING_MASK_C
;
183 * Next recalculate the next sequence for the current position.
186 if (__predict_true(i
< MTPRNG_RLEN
- 1)) {
188 * Avoid doing % since it can be expensive.
189 * j = (i + MTPRNG_POS1) % MTPRNG_RLEN;
192 if (j
>= MTPRNG_RLEN
)
199 y
= MIX(y
, mt
->mt_elem
[mt
->mt_idx
]);
200 mt
->mt_elem
[i
] = mt
->mt_elem
[j
] ^ (y
>> 1) ^ MATRIX_A(y
);
203 * Return the value calculated in the first step.
209 * This is a non-standard routine which attempts to return a cryptographically
210 * strong random number by collapsing 2 32bit values outputed by the twister
211 * into one 32bit value.
214 mtprng_random(struct mtprng_state
*mt
)
218 mt
->mt_count
= (mt
->mt_count
+ 13) & 31;
219 a
= mtprng_rawrandom(mt
);
220 a
= (a
<< mt
->mt_count
) | (a
>> (32 - mt
->mt_count
));
221 return a
+ mtprng_rawrandom(mt
);