1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 |
- # Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
- #
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- #
- # https://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- """Functions for generating random numbers."""
- # Source inspired by code by Yesudeep Mangalapilly <yesudeep@gmail.com>
- import os
- import struct
- from rsa import common, transform
- def read_random_bits(nbits: int) -> bytes:
- """Reads 'nbits' random bits.
- If nbits isn't a whole number of bytes, an extra byte will be appended with
- only the lower bits set.
- """
- nbytes, rbits = divmod(nbits, 8)
- # Get the random bytes
- randomdata = os.urandom(nbytes)
- # Add the remaining random bits
- if rbits > 0:
- randomvalue = ord(os.urandom(1))
- randomvalue >>= 8 - rbits
- randomdata = struct.pack("B", randomvalue) + randomdata
- return randomdata
- def read_random_int(nbits: int) -> int:
- """Reads a random integer of approximately nbits bits."""
- randomdata = read_random_bits(nbits)
- value = transform.bytes2int(randomdata)
- # Ensure that the number is large enough to just fill out the required
- # number of bits.
- value |= 1 << (nbits - 1)
- return value
- def read_random_odd_int(nbits: int) -> int:
- """Reads a random odd integer of approximately nbits bits.
- >>> read_random_odd_int(512) & 1
- 1
- """
- value = read_random_int(nbits)
- # Make sure it's odd
- return value | 1
- def randint(maxvalue: int) -> int:
- """Returns a random integer x with 1 <= x <= maxvalue
- May take a very long time in specific situations. If maxvalue needs N bits
- to store, the closer maxvalue is to (2 ** N) - 1, the faster this function
- is.
- """
- bit_size = common.bit_size(maxvalue)
- tries = 0
- while True:
- value = read_random_int(bit_size)
- if value <= maxvalue:
- break
- if tries % 10 == 0 and tries:
- # After a lot of tries to get the right number of bits but still
- # smaller than maxvalue, decrease the number of bits by 1. That'll
- # dramatically increase the chances to get a large enough number.
- bit_size -= 1
- tries += 1
- return value
|