2 Adapted from http://javarng.googlecode.com/svn/trunk/com/modp/random/BlumBlumShub.java
4 Original license follows:-
6 Copyright 2005, Nick Galbreath -- nickg [at] modp [dot] com
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions are
13 Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
16 Redistributions in binary form must reproduce the above copyright
17 notice, this list of conditions and the following disclaimer in the
18 documentation and/or other materials provided with the distribution.
20 Neither the name of the modp.com nor the names of its
21 contributors may be used to endorse or promote products derived from
22 this software without specific prior written permission.
24 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 This is the standard "new" BSD license:
37 http://www.opensource.org/licenses/bsd-license.php
45 class BlumBlumShub(object):
47 def getPrime(self, bits):
49 Generate appropriate prime number for use in Blum-Blum-Shub.
51 This generates the appropriate primes (p = 3 mod 4) needed to compute the
52 "n-value" for Blum-Blum-Shub.
53 bits - Number of bits in prime
57 p = primes.bigppr(bits);
62 def generateN(self, bits):
64 This generates the "n value" for use in the Blum-Blum-Shub algorithm.
65 bits - The number of bits of security
68 p = self.getPrime(bits/2)
69 q = self.getPrime(bits/2)
71 # make sure p != q (almost always true, but just in case, check)
73 q = getPrime(self, bits/2);
75 # print "GenerateN - p = " + repr(p) + ", q = " + repr(q)
79 def __init__(self, bits):
81 Constructor, specifing bits for n.
85 self.n = self.generateN(bits)
87 # print "n set to " + repr(self.n)
88 length = self.bitLen(self.n)
89 seed = random.getrandbits(length)
92 def setSeed(self, seed):
94 Sets or resets the seed value and internal state.
99 self.state = seed % self.n
102 " Get the bit lengh of a positive number"
110 def next(self, numBits):
111 "Returns up to numBit random bits"
114 for i in range(numBits,0,-1):
115 self.state = (self.state**2) % self.n
116 result = (result << 1) | (self.state&1)
121 def sample(self, population, k):
122 """Chooses k unique random elements from a population sequence.
124 Returns a new list containing elements from the population while
125 leaving the original population unchanged. The resulting list is
126 in selection order so that all sub-slices will also be valid random
127 samples. This allows raffle winners (the sample) to be partitioned
128 into grand prize and second place winners (the subslices).
130 Members of the population need not be hashable or unique. If the
131 population contains repeats, then each occurrence is a possible
132 selection in the sample.
134 To choose a sample in a range of integers, use xrange as an argument.
135 This is especially fast and space efficient for sampling from a
136 large population: sample(xrange(10000000), 60)
139 # Sampling without replacement entails tracking either potential
140 # selections (the pool) in a list or previous selections in a set.
142 # When the number of selections is small compared to the
143 # population, then tracking selections is efficient, requiring
144 # only a small set and an occasional reselection. For
145 # a larger number of selections, the pool tracking method is
146 # preferred since the list takes less space than the
147 # set and it doesn't suffer from frequent reselections.
151 raise ValueError("sample larger than population")
153 return float(self.next())/9999999999
156 setsize = 21 # size of a small set minus size of an empty list
158 setsize += 4 ** _ceil(_log(k * 3, 4)) # table size for big sets
159 if n <= setsize or hasattr(population, "keys"):
160 # An n-length list is smaller than a k-length set, or this is a
161 # mapping type so the other algorithm wouldn't work.
162 pool = list(population)
163 for i in xrange(k): # invariant: non-selected at [0,n-i)
164 j = _int(random() * (n-i))
167 pool[j] = pool[n-i-1] # move non-selected item into vacancy
171 selected_add = selected.add
173 j = _int(random() * n)
176 j = _int(random() * n)
178 result[i] = population[j]
179 except (TypeError, KeyError): # handle (at least) sets
180 if isinstance(population, list):
182 return self.sample(tuple(population), k)
189 bbs = BlumBlumShub(159);
191 #print "Generating 10 numbers"
192 for i in range (0,10):
195 #print bbs.sample(range(10),5)
196 if __name__ == "__main__":