@@ -30,43 +30,26 @@ def orderlen(order):
3030
3131def randrange (order , entropy = None ):
3232 """Return a random integer k such that 1 <= k < order, uniformly
33- distributed across that range. For simplicity, this only behaves well if
34- 'order' is fairly close (but below) a power of 256. The try-try-again
35- algorithm we use takes longer and longer time (on average) to complete as
36- 'order' falls, rising to a maximum of avg=512 loops for the worst-case
37- (256**k)+1 . All of the standard curves behave well. There is a cutoff at
38- 10k loops (which raises RuntimeError) to prevent an infinite loop when
39- something is really broken like the entropy function not working.
33+ distributed across that range. Worst case should be a mean of 2 loops at (2**k)+2.
4034
4135 Note that this function is not declared to be forwards-compatible: we may
4236 change the behavior in future releases. The entropy= argument (which
4337 should get a callable that behaves like os.urandom) can be used to
4438 achieve stability within a given release (for repeatable unit tests), but
4539 should not be used as a long-term-compatible key generation algorithm.
4640 """
47- # we could handle arbitrary orders (even 256**k+1) better if we created
48- # candidates bit-wise instead of byte-wise, which would reduce the
49- # worst-case behavior to avg=2 loops, but that would be more complex. The
50- # change would be to round the order up to a power of 256, subtract one
51- # (to get 0xffff..), use that to get a byte-long mask for the top byte,
52- # generate the len-1 entropy bytes, generate one extra byte and mask off
53- # the top bits, then combine it with the rest. Requires jumping back and
54- # forth between strings and integers a lot.
55-
41+ assert order > 1
5642 if entropy is None :
5743 entropy = os .urandom
58- assert order > 1
59- bytes = orderlen (order )
60- dont_try_forever = 10000 # gives about 2**-60 failures for worst case
61- while dont_try_forever > 0 :
62- dont_try_forever -= 1
63- candidate = string_to_number (entropy (bytes )) + 1
64- if 1 <= candidate < order :
65- return candidate
66- continue
67- raise RuntimeError ("randrange() tried hard but gave up, either something"
68- " is very wrong or you got realllly unlucky. Order was"
69- " %x" % order )
44+ upper_2 = (order - 2 ).bit_length () or 1
45+ upper_256 = int (upper_2 / 8 + 1 );
46+ while True : #I don't think we need a counter with bit-wise randrange
47+ ent_256 = entropy (upper_256 )
48+ ent_2 = '' .join (bin (x )[2 :].zfill (8 ) for x in ent_256 )
49+ rand_num = int (ent_2 [:upper_2 ], base = 2 ) + 1
50+ if 0 < rand_num < order : return rand_num
51+ else :continue
52+
7053
7154
7255class PRNG :
0 commit comments