1 # Copyright (C) 2009 Nominum, Inc.
3 # Permission to use, copy, modify, and distribute this software and its
4 # documentation for any purpose with or without fee is hereby granted,
5 # provided that the above copyright notice and this permission notice
6 # appear in all copies.
8 # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
9 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
11 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
14 # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 import threading as _threading
21 import dummy_threading as _threading
23 class EntropyPool(object):
24 def __init__(self, seed=None):
28 self.lock = _threading.Lock()
31 self.hash = hashlib.sha1()
42 self.pool = '\0' * self.hash_len
49 def stir(self, entropy, already_locked=False):
50 if not already_locked:
53 bytes = [ord(c) for c in self.pool]
55 if self.pool_index == self.hash_len:
58 bytes[self.pool_index] ^= b
60 self.pool = ''.join([chr(c) for c in bytes])
62 if not already_locked:
65 def _maybe_seed(self):
71 r = file('/dev/urandom', 'r', 0)
77 seed = str(time.time())
85 if self.digest is None or self.next_byte == self.hash_len:
86 self.hash.update(self.pool)
87 self.digest = self.hash.digest()
88 self.stir(self.digest, True)
90 value = ord(self.digest[self.next_byte])
97 return self.random_8() * 256 + self.random_8()
100 return self.random_16() * 65536 + self.random_16()
102 def random_between(self, first, last):
103 size = last - first + 1
104 if size > 4294967296L:
105 raise ValueError('too big')
107 rand = self.random_32
110 rand = self.random_16
115 return (first + size * rand() // (max + 1))
120 return pool.random_16()
122 def between(first, last):
123 return pool.random_between(first, last)