Numbers.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. # ===================================================================
  2. #
  3. # Copyright (c) 2014, Legrandin <helderijs@gmail.com>
  4. # All rights reserved.
  5. #
  6. # Redistribution and use in source and binary forms, with or without
  7. # modification, are permitted provided that the following conditions
  8. # are met:
  9. #
  10. # 1. Redistributions of source code must retain the above copyright
  11. # notice, this list of conditions and the following disclaimer.
  12. # 2. Redistributions in binary form must reproduce the above copyright
  13. # notice, this list of conditions and the following disclaimer in
  14. # the documentation and/or other materials provided with the
  15. # distribution.
  16. #
  17. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  20. # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  21. # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23. # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  25. # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  26. # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  27. # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  28. # POSSIBILITY OF SUCH DAMAGE.
  29. # ===================================================================
  30. """Fast, arbitrary precision integers.
  31. :undocumented: __package__
  32. """
  33. __all__ = ["Integer"]
  34. from Crypto.Util.py3compat import *
  35. from Crypto import Random
  36. try:
  37. from Crypto.Math._Numbers_gmp import Integer
  38. from Crypto.Math._Numbers_gmp import implementation as _implementation
  39. except (ImportError, OSError):
  40. from Crypto.Math._Numbers_int import Integer
  41. _implementation = { }
  42. def _random(**kwargs):
  43. """Generate a random natural integer of a certain size.
  44. :Keywords:
  45. exact_bits : positive integer
  46. The length in bits of the resulting random Integer number.
  47. The number is guaranteed to fulfil the relation:
  48. 2^bits > result >= 2^(bits - 1)
  49. max_bits : positive integer
  50. The maximum length in bits of the resulting random Integer number.
  51. The number is guaranteed to fulfil the relation:
  52. 2^bits > result >=0
  53. randfunc : callable
  54. A function that returns a random byte string. The length of the
  55. byte string is passed as parameter. Optional.
  56. If not provided (or ``None``), randomness is read from the system RNG.
  57. :Return: a Integer object
  58. """
  59. exact_bits = kwargs.pop("exact_bits", None)
  60. max_bits = kwargs.pop("max_bits", None)
  61. randfunc = kwargs.pop("randfunc", None)
  62. if randfunc is None:
  63. randfunc = Random.new().read
  64. if exact_bits is None and max_bits is None:
  65. raise ValueError("Either 'exact_bits' or 'max_bits' must be specified")
  66. if exact_bits is not None and max_bits is not None:
  67. raise ValueError("'exact_bits' and 'max_bits' are mutually exclusive")
  68. bits = exact_bits or max_bits
  69. bytes_needed = ((bits - 1) // 8) + 1
  70. significant_bits_msb = 8 - (bytes_needed * 8 - bits)
  71. msb = bord(randfunc(1)[0])
  72. if exact_bits is not None:
  73. msb |= 1 << (significant_bits_msb - 1)
  74. msb &= (1 << significant_bits_msb) - 1
  75. return Integer.from_bytes(bchr(msb) + randfunc(bytes_needed - 1))
  76. def _random_range(**kwargs):
  77. """Generate a random integer within a given internal.
  78. :Keywords:
  79. min_inclusive : integer
  80. The lower end of the interval (inclusive).
  81. max_inclusive : integer
  82. The higher end of the interval (inclusive).
  83. max_exclusive : integer
  84. The higher end of the interval (exclusive).
  85. randfunc : callable
  86. A function that returns a random byte string. The length of the
  87. byte string is passed as parameter. Optional.
  88. If not provided (or ``None``), randomness is read from the system RNG.
  89. :Returns:
  90. An Integer randomly taken in the given interval.
  91. """
  92. min_inclusive = kwargs.pop("min_inclusive", None)
  93. max_inclusive = kwargs.pop("max_inclusive", None)
  94. max_exclusive = kwargs.pop("max_exclusive", None)
  95. randfunc = kwargs.pop("randfunc", None)
  96. if kwargs:
  97. raise ValueError("Unknown keywords: " + str(kwargs.keys))
  98. if None not in (max_inclusive, max_exclusive):
  99. raise ValueError("max_inclusive and max_exclusive cannot be both"
  100. " specified")
  101. if max_exclusive is not None:
  102. max_inclusive = max_exclusive - 1
  103. if None in (min_inclusive, max_inclusive):
  104. raise ValueError("Missing keyword to identify the interval")
  105. if randfunc is None:
  106. randfunc = Random.new().read
  107. norm_maximum = max_inclusive - min_inclusive
  108. bits_needed = Integer(norm_maximum).size_in_bits()
  109. norm_candidate = -1
  110. while not 0 <= norm_candidate <= norm_maximum:
  111. norm_candidate = _random(
  112. max_bits=bits_needed,
  113. randfunc=randfunc
  114. )
  115. return norm_candidate + min_inclusive
  116. Integer.random = staticmethod(_random)
  117. Integer.random_range = staticmethod(_random_range)