Spaces:
Runtime error
Runtime error
| # =================================================================== | |
| # | |
| # Copyright (c) 2018, Helder Eijs <helderijs@gmail.com> | |
| # All rights reserved. | |
| # | |
| # Redistribution and use in source and binary forms, with or without | |
| # modification, are permitted provided that the following conditions | |
| # are met: | |
| # | |
| # 1. Redistributions of source code must retain the above copyright | |
| # notice, this list of conditions and the following disclaimer. | |
| # 2. Redistributions in binary form must reproduce the above copyright | |
| # notice, this list of conditions and the following disclaimer in | |
| # the documentation and/or other materials provided with the | |
| # distribution. | |
| # | |
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
| # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | |
| # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| # POSSIBILITY OF SUCH DAMAGE. | |
| # =================================================================== | |
| import abc | |
| from Crypto.Util.py3compat import iter_range, bord, bchr, ABC | |
| from Crypto import Random | |
| class IntegerBase(ABC): | |
| # Conversions | |
| def __int__(self): | |
| pass | |
| def __str__(self): | |
| pass | |
| def __repr__(self): | |
| pass | |
| def to_bytes(self, block_size=0, byteorder='big'): | |
| pass | |
| def from_bytes(byte_string, byteorder='big'): | |
| pass | |
| # Relations | |
| def __eq__(self, term): | |
| pass | |
| def __ne__(self, term): | |
| pass | |
| def __lt__(self, term): | |
| pass | |
| def __le__(self, term): | |
| pass | |
| def __gt__(self, term): | |
| pass | |
| def __ge__(self, term): | |
| pass | |
| def __nonzero__(self): | |
| pass | |
| __bool__ = __nonzero__ | |
| def is_negative(self): | |
| pass | |
| # Arithmetic operations | |
| def __add__(self, term): | |
| pass | |
| def __sub__(self, term): | |
| pass | |
| def __mul__(self, factor): | |
| pass | |
| def __floordiv__(self, divisor): | |
| pass | |
| def __mod__(self, divisor): | |
| pass | |
| def inplace_pow(self, exponent, modulus=None): | |
| pass | |
| def __pow__(self, exponent, modulus=None): | |
| pass | |
| def __abs__(self): | |
| pass | |
| def sqrt(self, modulus=None): | |
| pass | |
| def __iadd__(self, term): | |
| pass | |
| def __isub__(self, term): | |
| pass | |
| def __imul__(self, term): | |
| pass | |
| def __imod__(self, term): | |
| pass | |
| # Boolean/bit operations | |
| def __and__(self, term): | |
| pass | |
| def __or__(self, term): | |
| pass | |
| def __rshift__(self, pos): | |
| pass | |
| def __irshift__(self, pos): | |
| pass | |
| def __lshift__(self, pos): | |
| pass | |
| def __ilshift__(self, pos): | |
| pass | |
| def get_bit(self, n): | |
| pass | |
| # Extra | |
| def is_odd(self): | |
| pass | |
| def is_even(self): | |
| pass | |
| def size_in_bits(self): | |
| pass | |
| def size_in_bytes(self): | |
| pass | |
| def is_perfect_square(self): | |
| pass | |
| def fail_if_divisible_by(self, small_prime): | |
| pass | |
| def multiply_accumulate(self, a, b): | |
| pass | |
| def set(self, source): | |
| pass | |
| def inplace_inverse(self, modulus): | |
| pass | |
| def inverse(self, modulus): | |
| pass | |
| def gcd(self, term): | |
| pass | |
| def lcm(self, term): | |
| pass | |
| def jacobi_symbol(a, n): | |
| pass | |
| def _tonelli_shanks(n, p): | |
| """Tonelli-shanks algorithm for computing the square root | |
| of n modulo a prime p. | |
| n must be in the range [0..p-1]. | |
| p must be at least even. | |
| The return value r is the square root of modulo p. If non-zero, | |
| another solution will also exist (p-r). | |
| Note we cannot assume that p is really a prime: if it's not, | |
| we can either raise an exception or return the correct value. | |
| """ | |
| # See https://rosettacode.org/wiki/Tonelli-Shanks_algorithm | |
| if n in (0, 1): | |
| return n | |
| if p % 4 == 3: | |
| root = pow(n, (p + 1) // 4, p) | |
| if pow(root, 2, p) != n: | |
| raise ValueError("Cannot compute square root") | |
| return root | |
| s = 1 | |
| q = (p - 1) // 2 | |
| while not (q & 1): | |
| s += 1 | |
| q >>= 1 | |
| z = n.__class__(2) | |
| while True: | |
| euler = pow(z, (p - 1) // 2, p) | |
| if euler == 1: | |
| z += 1 | |
| continue | |
| if euler == p - 1: | |
| break | |
| # Most probably p is not a prime | |
| raise ValueError("Cannot compute square root") | |
| m = s | |
| c = pow(z, q, p) | |
| t = pow(n, q, p) | |
| r = pow(n, (q + 1) // 2, p) | |
| while t != 1: | |
| for i in iter_range(0, m): | |
| if pow(t, 2**i, p) == 1: | |
| break | |
| if i == m: | |
| raise ValueError("Cannot compute square root of %d mod %d" % (n, p)) | |
| b = pow(c, 2**(m - i - 1), p) | |
| m = i | |
| c = b**2 % p | |
| t = (t * b**2) % p | |
| r = (r * b) % p | |
| if pow(r, 2, p) != n: | |
| raise ValueError("Cannot compute square root") | |
| return r | |
| def random(cls, **kwargs): | |
| """Generate a random natural integer of a certain size. | |
| :Keywords: | |
| exact_bits : positive integer | |
| The length in bits of the resulting random Integer number. | |
| The number is guaranteed to fulfil the relation: | |
| 2^bits > result >= 2^(bits - 1) | |
| max_bits : positive integer | |
| The maximum length in bits of the resulting random Integer number. | |
| The number is guaranteed to fulfil the relation: | |
| 2^bits > result >=0 | |
| randfunc : callable | |
| A function that returns a random byte string. The length of the | |
| byte string is passed as parameter. Optional. | |
| If not provided (or ``None``), randomness is read from the system RNG. | |
| :Return: a Integer object | |
| """ | |
| exact_bits = kwargs.pop("exact_bits", None) | |
| max_bits = kwargs.pop("max_bits", None) | |
| randfunc = kwargs.pop("randfunc", None) | |
| if randfunc is None: | |
| randfunc = Random.new().read | |
| if exact_bits is None and max_bits is None: | |
| raise ValueError("Either 'exact_bits' or 'max_bits' must be specified") | |
| if exact_bits is not None and max_bits is not None: | |
| raise ValueError("'exact_bits' and 'max_bits' are mutually exclusive") | |
| bits = exact_bits or max_bits | |
| bytes_needed = ((bits - 1) // 8) + 1 | |
| significant_bits_msb = 8 - (bytes_needed * 8 - bits) | |
| msb = bord(randfunc(1)[0]) | |
| if exact_bits is not None: | |
| msb |= 1 << (significant_bits_msb - 1) | |
| msb &= (1 << significant_bits_msb) - 1 | |
| return cls.from_bytes(bchr(msb) + randfunc(bytes_needed - 1)) | |
| def random_range(cls, **kwargs): | |
| """Generate a random integer within a given internal. | |
| :Keywords: | |
| min_inclusive : integer | |
| The lower end of the interval (inclusive). | |
| max_inclusive : integer | |
| The higher end of the interval (inclusive). | |
| max_exclusive : integer | |
| The higher end of the interval (exclusive). | |
| randfunc : callable | |
| A function that returns a random byte string. The length of the | |
| byte string is passed as parameter. Optional. | |
| If not provided (or ``None``), randomness is read from the system RNG. | |
| :Returns: | |
| An Integer randomly taken in the given interval. | |
| """ | |
| min_inclusive = kwargs.pop("min_inclusive", None) | |
| max_inclusive = kwargs.pop("max_inclusive", None) | |
| max_exclusive = kwargs.pop("max_exclusive", None) | |
| randfunc = kwargs.pop("randfunc", None) | |
| if kwargs: | |
| raise ValueError("Unknown keywords: " + str(kwargs.keys)) | |
| if None not in (max_inclusive, max_exclusive): | |
| raise ValueError("max_inclusive and max_exclusive cannot be both" | |
| " specified") | |
| if max_exclusive is not None: | |
| max_inclusive = max_exclusive - 1 | |
| if None in (min_inclusive, max_inclusive): | |
| raise ValueError("Missing keyword to identify the interval") | |
| if randfunc is None: | |
| randfunc = Random.new().read | |
| norm_maximum = max_inclusive - min_inclusive | |
| bits_needed = cls(norm_maximum).size_in_bits() | |
| norm_candidate = -1 | |
| while not 0 <= norm_candidate <= norm_maximum: | |
| norm_candidate = cls.random( | |
| max_bits=bits_needed, | |
| randfunc=randfunc | |
| ) | |
| return norm_candidate + min_inclusive | |