/ adafruit_rsa / randnum.py
randnum.py
  1  # -*- coding: utf-8 -*-
  2  #
  3  #  Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
  4  #
  5  #  Licensed under the Apache License, Version 2.0 (the "License");
  6  #  you may not use this file except in compliance with the License.
  7  #  You may obtain a copy of the License at
  8  #
  9  #      https://www.apache.org/licenses/LICENSE-2.0
 10  #
 11  #  Unless required by applicable law or agreed to in writing, software
 12  #  distributed under the License is distributed on an "AS IS" BASIS,
 13  #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  #  See the License for the specific language governing permissions and
 15  #  limitations under the License.
 16  
 17  """Functions for generating random numbers."""
 18  
 19  # Source inspired by code by Yesudeep Mangalapilly <yesudeep@gmail.com>
 20  
 21  import os
 22  
 23  from adafruit_rsa import common, transform
 24  from adafruit_rsa._compat import byte
 25  
 26  __version__ = "0.0.0-auto.0"
 27  __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_RSA.git"
 28  
 29  
 30  def read_random_bits(nbits):
 31      """Reads 'nbits' random bits.
 32  
 33      If nbits isn't a whole number of bytes, an extra byte will be appended with
 34      only the lower bits set.
 35      """
 36  
 37      nbytes, rbits = divmod(nbits, 8)
 38  
 39      # Get the random bytes
 40      randomdata = os.urandom(nbytes)
 41  
 42      # Add the remaining random bits
 43      if rbits > 0:
 44          randomvalue = ord(os.urandom(1))
 45          randomvalue >>= 8 - rbits
 46          randomdata = byte(randomvalue) + randomdata
 47  
 48      return randomdata
 49  
 50  
 51  def read_random_int(nbits):
 52      """Reads a random integer of approximately nbits bits.
 53      """
 54  
 55      randomdata = read_random_bits(nbits)
 56      value = transform.bytes2int(randomdata)
 57  
 58      # Ensure that the number is large enough to just fill out the required
 59      # number of bits.
 60      value |= 1 << (nbits - 1)
 61  
 62      return value
 63  
 64  
 65  def read_random_odd_int(nbits):
 66      """Reads a random odd integer of approximately nbits bits.
 67  
 68      >>> read_random_odd_int(512) & 1
 69      1
 70      """
 71  
 72      value = read_random_int(nbits)
 73  
 74      # Make sure it's odd
 75      return value | 1
 76  
 77  
 78  def randint(maxvalue):
 79      """Returns a random integer x with 1 <= x <= maxvalue
 80  
 81      May take a very long time in specific situations. If maxvalue needs N bits
 82      to store, the closer maxvalue is to (2 ** N) - 1, the faster this function
 83      is.
 84      """
 85  
 86      bit_size = common.bit_size(maxvalue)
 87  
 88      tries = 0
 89      while True:
 90          value = read_random_int(bit_size)
 91          if value <= maxvalue:
 92              break
 93  
 94          if tries % 10 == 0 and tries:
 95              # After a lot of tries to get the right number of bits but still
 96              # smaller than maxvalue, decrease the number of bits by 1. That'll
 97              # dramatically increase the chances to get a large enough number.
 98              bit_size -= 1
 99          tries += 1
100  
101      return value