5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2008 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
20 #include "silcruntime.h"
22 /************************* Types and definitions ****************************/
24 /* Random number state context size */
25 #define SILC_RAND_STATE_SIZE 624
26 #define SILC_RAND_STATE_FULL_SIZE ((SILC_RAND_STATE_SIZE + 1) * \
29 /* State position offset */
30 #define SILC_RAND_STATE_POS (SILC_RAND_STATE_SIZE + 1) - 1
32 /************************ Static utility functions **************************/
34 /* Refresh the state */
36 void silc_rand_refresh(SilcUInt32 *rs)
40 for (i = 0; i < SILC_RAND_STATE_SIZE - 1; i++) {
41 c = (rs[i] & 0x80000000UL) | (rs[i + 1] & 0x7fffffffUL);
43 rs[i] = rs[(i + 397) % SILC_RAND_STATE_SIZE] ^ (c >> 1) ^ 0x9908b0dfUL;
45 rs[i] = rs[(i + 397) % SILC_RAND_STATE_SIZE] ^ (c >> 1);
48 c = (rs[i] & 0x80000000UL) | (rs[0] & 0x7fffffffUL);
50 rs[i] = rs[(i + 397) % SILC_RAND_STATE_SIZE] ^ (c >> 1) ^ 0x9908b0dfUL;
52 rs[i] = rs[(i + 397) % SILC_RAND_STATE_SIZE] ^ (c >> 1);
54 rs[SILC_RAND_STATE_POS] = 0;
59 static void silc_rand_seed_state(SilcUInt32 *rs, SilcUInt32 seed)
64 for (i = 1; i < SILC_RAND_STATE_SIZE; i++) {
66 rs[i] = (1812433253UL * ((c ^ (c >> 30)) + 1));
69 silc_rand_refresh(rs);
72 /* Return random state or create it. */
74 static SilcUInt32 *silc_rand_state(SilcBool seed)
78 rs = silc_global_get_var("srtrs", TRUE);
80 rs = silc_global_set_var("srtrs", SILC_RAND_STATE_FULL_SIZE, NULL, TRUE);
85 silc_rand_seed_state(rs, (SilcUInt32)silc_time_usec());
91 /* Temper next position and return the value */
93 SilcUInt32 silc_rand_temper(SilcUInt32 *rs)
97 /* Refresh if necessary */
98 if (++rs[SILC_RAND_STATE_POS] >= SILC_RAND_STATE_SIZE)
99 silc_rand_refresh(rs);
102 val = rs[rs[SILC_RAND_STATE_POS]];
103 val = val ^ (val >> 11);
104 val = val ^ ((val << 7) & 0x9d2c5680UL);
105 val = val ^ ((val << 15) & 0xefc60000UL);
106 return val ^ (val >> 18);
109 /******************************* SILC Rand API ******************************/
111 /* Seed the generator */
113 void silc_rand_seed(SilcUInt32 seed)
117 rs = silc_rand_state(FALSE);
121 silc_rand_seed_state(rs, seed);
124 /* Return 32-bit random number */
126 SilcUInt32 silc_rand(void)
130 rs = silc_rand_state(TRUE);
132 return 0x23456789 + (SilcUInt32)silc_time_usec();
134 return silc_rand_temper(rs);
137 /* Return 64-bit random number */
139 SilcUInt64 silc_rand64(void)
143 rs = silc_rand_state(TRUE);
145 return 0x1234567891234567 + silc_time_usec();
147 return (SilcUInt64)(((SilcUInt64)silc_rand_temper(rs) << 32) |
148 silc_rand_temper(rs));