Added SILC Rand API, SILC Global Variables API and silcruntime.h.in
[runtime.git] / lib / silcutil / silcrand.c
1 /*
2
3   silcrand.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2008 Pekka Riikonen
8
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.
12
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.
17
18 */
19
20 #include "silcruntime.h"
21
22 /************************* Types and definitions ****************************/
23
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) * \
27                                    sizeof(SilcUInt32))
28
29 /* State position offset */
30 #define SILC_RAND_STATE_POS (SILC_RAND_STATE_SIZE + 1) - 1
31
32 /************************ Static utility functions **************************/
33
34 /* Refresh the state */
35
36 void silc_rand_refresh(SilcUInt32 *rs)
37 {
38   SilcUInt32 i, c;
39
40   for (i = 0; i < SILC_RAND_STATE_SIZE - 1; i++) {
41     c = (rs[i] & 0x80000000UL) | (rs[i + 1] & 0x7fffffffUL);
42     if (c & 1)
43       rs[i] = rs[(i + 397) % SILC_RAND_STATE_SIZE] ^ (c >> 1) ^ 0x9908b0dfUL;
44     else
45       rs[i] = rs[(i + 397) % SILC_RAND_STATE_SIZE] ^ (c >> 1);
46   }
47
48   c = (rs[i] & 0x80000000UL) | (rs[0] & 0x7fffffffUL);
49   if (c & 1)
50     rs[i] = rs[(i + 397) % SILC_RAND_STATE_SIZE] ^ (c >> 1) ^ 0x9908b0dfUL;
51   else
52     rs[i] = rs[(i + 397) % SILC_RAND_STATE_SIZE] ^ (c >> 1);
53
54   rs[SILC_RAND_STATE_POS] = 0;
55 }
56
57 /* Seed */
58
59 static void silc_rand_seed_state(SilcUInt32 *rs, SilcUInt32 seed)
60 {
61   SilcUInt32 c, i;
62
63   rs[0] = seed;
64   for (i = 1; i < SILC_RAND_STATE_SIZE; i++) {
65     c = rs[i - 1];
66     rs[i] = (1812433253UL * ((c ^ (c >> 30)) + 1));
67   }
68
69   silc_rand_refresh(rs);
70 }
71
72 /* Return random state or create it. */
73
74 static SilcUInt32 *silc_rand_state(SilcBool seed)
75 {
76   SilcUInt32 *rs;
77
78   rs = silc_global_get_var("srtrs", TRUE);
79   if (!rs) {
80     rs = silc_global_set_var("srtrs", SILC_RAND_STATE_FULL_SIZE, NULL, TRUE);
81     if (!rs)
82       return NULL;
83
84     if (seed)
85       silc_rand_seed_state(rs, (SilcUInt32)silc_time_usec());
86   }
87
88   return rs;
89 }
90
91 /* Temper next position and return the value */
92
93 SilcUInt32 silc_rand_temper(SilcUInt32 *rs)
94 {
95   SilcUInt32 val;
96
97   /* Refresh if necessary */
98   if (++rs[SILC_RAND_STATE_POS] >= SILC_RAND_STATE_SIZE)
99     silc_rand_refresh(rs);
100
101   /* Temper */
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);
107 }
108
109 /******************************* SILC Rand API ******************************/
110
111 /* Seed the generator */
112
113 void silc_rand_seed(SilcUInt32 seed)
114 {
115   SilcUInt32 *rs;
116
117   rs = silc_rand_state(FALSE);
118   if (!rs)
119     return;
120
121   silc_rand_seed_state(rs, seed);
122 }
123
124 /* Return 32-bit random number */
125
126 SilcUInt32 silc_rand(void)
127 {
128   SilcUInt32 *rs;
129
130   rs = silc_rand_state(TRUE);
131   if (!rs)
132     return 0x23456789 + (SilcUInt32)silc_time_usec();
133
134   return silc_rand_temper(rs);
135 }
136
137 /* Return 64-bit random number */
138
139 SilcUInt64 silc_rand64(void)
140 {
141   SilcUInt32 *rs;
142
143   rs = silc_rand_state(TRUE);
144   if (!rs)
145     return 0x1234567891234567 + silc_time_usec();
146
147   return (SilcUInt64)(((SilcUInt64)silc_rand_temper(rs) << 32) |
148                       silc_rand_temper(rs));
149 }