diff options
Diffstat (limited to 'lib/random.c')
| -rw-r--r-- | lib/random.c | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/lib/random.c b/lib/random.c new file mode 100644 index 0000000..a4761b6 --- /dev/null +++ b/lib/random.c | |||
| @@ -0,0 +1,83 @@ | |||
| 1 | #include "random.h" | ||
| 2 | #include <stdbool.h> | ||
| 3 | #include <stdint.h> | ||
| 4 | #include "debug.h" | ||
| 5 | |||
| 6 | /* RC4-based pseudo-random number generator (PRNG). | ||
| 7 | |||
| 8 | RC4 is a stream cipher. We're not using it here for its | ||
| 9 | cryptographic properties, but because it is easy to implement | ||
| 10 | and its output is plenty random for non-cryptographic | ||
| 11 | purposes. | ||
| 12 | |||
| 13 | See http://en.wikipedia.org/wiki/RC4_(cipher) for information | ||
| 14 | on RC4.*/ | ||
| 15 | |||
| 16 | /* RC4 state. */ | ||
| 17 | static uint8_t s[256]; /* S[]. */ | ||
| 18 | static uint8_t s_i, s_j; /* i, j. */ | ||
| 19 | |||
| 20 | /* Already initialized? */ | ||
| 21 | static bool inited; | ||
| 22 | |||
| 23 | /* Swaps the bytes pointed to by A and B. */ | ||
| 24 | static inline void | ||
| 25 | swap_byte (uint8_t *a, uint8_t *b) | ||
| 26 | { | ||
| 27 | uint8_t t = *a; | ||
| 28 | *a = *b; | ||
| 29 | *b = t; | ||
| 30 | } | ||
| 31 | |||
| 32 | /* Initializes or reinitializes the PRNG with the given SEED. */ | ||
| 33 | void | ||
| 34 | random_init (unsigned seed) | ||
| 35 | { | ||
| 36 | uint8_t *seedp = (uint8_t *) &seed; | ||
| 37 | int i; | ||
| 38 | uint8_t j; | ||
| 39 | |||
| 40 | for (i = 0; i < 256; i++) | ||
| 41 | s[i] = i; | ||
| 42 | for (i = j = 0; i < 256; i++) | ||
| 43 | { | ||
| 44 | j += s[i] + seedp[i % sizeof seed]; | ||
| 45 | swap_byte (s + i, s + j); | ||
| 46 | } | ||
| 47 | |||
| 48 | s_i = s_j = 0; | ||
| 49 | inited = true; | ||
| 50 | } | ||
| 51 | |||
| 52 | /* Writes SIZE random bytes into BUF. */ | ||
| 53 | void | ||
| 54 | random_bytes (void *buf_, size_t size) | ||
| 55 | { | ||
| 56 | uint8_t *buf; | ||
| 57 | |||
| 58 | if (!inited) | ||
| 59 | random_init (0); | ||
| 60 | |||
| 61 | for (buf = buf_; size-- > 0; buf++) | ||
| 62 | { | ||
| 63 | uint8_t s_k; | ||
| 64 | |||
| 65 | s_i++; | ||
| 66 | s_j += s[s_i]; | ||
| 67 | swap_byte (s + s_i, s + s_j); | ||
| 68 | |||
| 69 | s_k = s[s_i] + s[s_j]; | ||
| 70 | *buf = s[s_k]; | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | /* Returns a pseudo-random unsigned long. | ||
| 75 | Use random_ulong() % n to obtain a random number in the range | ||
| 76 | 0...n (exclusive). */ | ||
| 77 | unsigned long | ||
| 78 | random_ulong (void) | ||
| 79 | { | ||
| 80 | unsigned long ul; | ||
| 81 | random_bytes (&ul, sizeof ul); | ||
| 82 | return ul; | ||
| 83 | } | ||
