diff options
author | Nick Mathewson <nickm@torproject.org> | 2012-04-09 11:30:46 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2012-04-09 11:30:46 -0400 |
commit | 3aa44159c53af1d6459a85dc1841c7c494d52464 (patch) | |
tree | bf545d67d57ab47bb0f262a3a9e78394c64162c0 /evutil.c | |
parent | e86af4b7e56ed5b7050cb4f41ae534f54748598c (diff) | |
download | libevent-3aa44159c53af1d6459a85dc1841c7c494d52464.tar.gz |
Tweak the new evutil_weakrand_() code
Make its state actually get seeded.
Document it more thoroughly.
Turn its state into a structure.
Fix a bug in evutil_weakrand_range_() where it could return the top of
the range.
Change its return type to ev_int32_t.
Add a quick unit test to make sure that the value of
evutil_weakrand_range_() is in range.
Diffstat (limited to 'evutil.c')
-rw-r--r-- | evutil.c | 49 |
1 files changed, 39 insertions, 10 deletions
@@ -2274,21 +2274,50 @@ evutil_getenv_(const char *varname) } ev_uint32_t -evutil_weakrand_(ev_uint32_t* seed) +evutil_weakrand_seed_(struct evutil_weakrand_state *state, ev_uint32_t seed) { - *seed = ((*seed) * 1103515245 + 12345) & 0x7fffffff; - return (*seed); + if (seed == 0) { + struct timeval tv; + evutil_gettimeofday(&tv, NULL); + seed = (ev_uint32_t)tv.tv_sec + (ev_uint32_t)tv.tv_usec; +#ifdef _WIN32 + seed += (ev_uint32_t) _getpid(); +#else + seed += (ev_uint32_t) getpid(); +#endif + } + state->seed = seed; + return seed; } -ev_uint32_t -evutil_weakrand_range_(ev_uint32_t* seed, ev_uint32_t top) +ev_int32_t +evutil_weakrand_(struct evutil_weakrand_state *state) +{ + /* This RNG implementation is a linear congruential generator, with + * modulus 2^31, multiplier 1103515245, and addend 12345. It's also + * used by OpenBSD, and by Glibc's TYPE_0 RNG. + * + * The linear congruential generator is not an industrial-strength + * RNG! It's fast, but it can have higher-order patterns. Notably, + * the low bits tend to have periodicity. + */ + state->seed = ((state->seed) * 1103515245 + 12345) & 0x7fffffff; + return (ev_int32_t)(state->seed); +} + +ev_int32_t +evutil_weakrand_range_(struct evutil_weakrand_state *state, ev_int32_t top) { - ev_uint32_t divisor, result; + ev_int32_t divisor, result; - divisor = EV_INT32_MAX / top; - do - result = evutil_weakrand_(seed) / divisor; - while (result > top); + /* We can't just do weakrand() % top, since the low bits of the LCG + * are less random than the high ones. (Specifically, since the LCG + * modulus is 2^N, every 2^m for m<N will divide the modulus, and so + * therefore the low m bits of the LCG will have period 2^m.) */ + divisor = EVUTIL_WEAKRAND_MAX / top; + do { + result = evutil_weakrand_(state) / divisor; + } while (result >= top); return result; } |