aboutsummaryrefslogtreecommitdiff
path: root/frozen_deps/Cryptodome/Math
diff options
context:
space:
mode:
Diffstat (limited to 'frozen_deps/Cryptodome/Math')
-rw-r--r--frozen_deps/Cryptodome/Math/Numbers.py42
-rw-r--r--frozen_deps/Cryptodome/Math/Numbers.pyi4
-rw-r--r--frozen_deps/Cryptodome/Math/Primality.py368
-rw-r--r--frozen_deps/Cryptodome/Math/Primality.pyi18
-rw-r--r--frozen_deps/Cryptodome/Math/_IntegerBase.py392
-rw-r--r--frozen_deps/Cryptodome/Math/_IntegerBase.pyi61
-rw-r--r--frozen_deps/Cryptodome/Math/_IntegerCustom.py111
-rw-r--r--frozen_deps/Cryptodome/Math/_IntegerCustom.pyi8
-rw-r--r--frozen_deps/Cryptodome/Math/_IntegerGMP.py708
-rw-r--r--frozen_deps/Cryptodome/Math/_IntegerGMP.pyi3
-rw-r--r--frozen_deps/Cryptodome/Math/_IntegerNative.py380
-rw-r--r--frozen_deps/Cryptodome/Math/_IntegerNative.pyi3
-rw-r--r--frozen_deps/Cryptodome/Math/__init__.py0
-rwxr-xr-xfrozen_deps/Cryptodome/Math/_modexp.cpython-38-x86_64-linux-gnu.sobin0 -> 207274 bytes
14 files changed, 2098 insertions, 0 deletions
diff --git a/frozen_deps/Cryptodome/Math/Numbers.py b/frozen_deps/Cryptodome/Math/Numbers.py
new file mode 100644
index 0000000..c9ff848
--- /dev/null
+++ b/frozen_deps/Cryptodome/Math/Numbers.py
@@ -0,0 +1,42 @@
+# ===================================================================
+#
+# Copyright (c) 2014, Legrandin <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.
+# ===================================================================
+
+__all__ = ["Integer"]
+
+try:
+ from Cryptodome.Math._IntegerGMP import IntegerGMP as Integer
+ from Cryptodome.Math._IntegerGMP import implementation as _implementation
+except (ImportError, OSError, AttributeError):
+ try:
+ from Cryptodome.Math._IntegerCustom import IntegerCustom as Integer
+ from Cryptodome.Math._IntegerCustom import implementation as _implementation
+ except (ImportError, OSError):
+ from Cryptodome.Math._IntegerNative import IntegerNative as Integer
+ _implementation = {}
diff --git a/frozen_deps/Cryptodome/Math/Numbers.pyi b/frozen_deps/Cryptodome/Math/Numbers.pyi
new file mode 100644
index 0000000..2285a3b
--- /dev/null
+++ b/frozen_deps/Cryptodome/Math/Numbers.pyi
@@ -0,0 +1,4 @@
+from Cryptodome.Math._IntegerBase import IntegerBase
+
+class Integer(IntegerBase):
+ pass
diff --git a/frozen_deps/Cryptodome/Math/Primality.py b/frozen_deps/Cryptodome/Math/Primality.py
new file mode 100644
index 0000000..08ea3ff
--- /dev/null
+++ b/frozen_deps/Cryptodome/Math/Primality.py
@@ -0,0 +1,368 @@
+# ===================================================================
+#
+# Copyright (c) 2014, Legrandin <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.
+# ===================================================================
+
+"""Functions to create and test prime numbers.
+
+:undocumented: __package__
+"""
+
+from Cryptodome import Random
+from Cryptodome.Math.Numbers import Integer
+
+from Cryptodome.Util.py3compat import iter_range
+
+COMPOSITE = 0
+PROBABLY_PRIME = 1
+
+
+def miller_rabin_test(candidate, iterations, randfunc=None):
+ """Perform a Miller-Rabin primality test on an integer.
+
+ The test is specified in Section C.3.1 of `FIPS PUB 186-4`__.
+
+ :Parameters:
+ candidate : integer
+ The number to test for primality.
+ iterations : integer
+ The maximum number of iterations to perform before
+ declaring a candidate a probable prime.
+ randfunc : callable
+ An RNG function where bases are taken from.
+
+ :Returns:
+ ``Primality.COMPOSITE`` or ``Primality.PROBABLY_PRIME``.
+
+ .. __: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
+ """
+
+ if not isinstance(candidate, Integer):
+ candidate = Integer(candidate)
+
+ if candidate in (1, 2, 3, 5):
+ return PROBABLY_PRIME
+
+ if candidate.is_even():
+ return COMPOSITE
+
+ one = Integer(1)
+ minus_one = Integer(candidate - 1)
+
+ if randfunc is None:
+ randfunc = Random.new().read
+
+ # Step 1 and 2
+ m = Integer(minus_one)
+ a = 0
+ while m.is_even():
+ m >>= 1
+ a += 1
+
+ # Skip step 3
+
+ # Step 4
+ for i in iter_range(iterations):
+
+ # Step 4.1-2
+ base = 1
+ while base in (one, minus_one):
+ base = Integer.random_range(min_inclusive=2,
+ max_inclusive=candidate - 2)
+ assert(2 <= base <= candidate - 2)
+
+ # Step 4.3-4.4
+ z = pow(base, m, candidate)
+ if z in (one, minus_one):
+ continue
+
+ # Step 4.5
+ for j in iter_range(1, a):
+ z = pow(z, 2, candidate)
+ if z == minus_one:
+ break
+ if z == one:
+ return COMPOSITE
+ else:
+ return COMPOSITE
+
+ # Step 5
+ return PROBABLY_PRIME
+
+
+def lucas_test(candidate):
+ """Perform a Lucas primality test on an integer.
+
+ The test is specified in Section C.3.3 of `FIPS PUB 186-4`__.
+
+ :Parameters:
+ candidate : integer
+ The number to test for primality.
+
+ :Returns:
+ ``Primality.COMPOSITE`` or ``Primality.PROBABLY_PRIME``.
+
+ .. __: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
+ """
+
+ if not isinstance(candidate, Integer):
+ candidate = Integer(candidate)
+
+ # Step 1
+ if candidate in (1, 2, 3, 5):
+ return PROBABLY_PRIME
+ if candidate.is_even() or candidate.is_perfect_square():
+ return COMPOSITE
+
+ # Step 2
+ def alternate():
+ value = 5
+ while True:
+ yield value
+ if value > 0:
+ value += 2
+ else:
+ value -= 2
+ value = -value
+
+ for D in alternate():
+ if candidate in (D, -D):
+ continue
+ js = Integer.jacobi_symbol(D, candidate)
+ if js == 0:
+ return COMPOSITE
+ if js == -1:
+ break
+ # Found D. P=1 and Q=(1-D)/4 (note that Q is guaranteed to be an integer)
+
+ # Step 3
+ # This is \delta(n) = n - jacobi(D/n)
+ K = candidate + 1
+ # Step 4
+ r = K.size_in_bits() - 1
+ # Step 5
+ # U_1=1 and V_1=P
+ U_i = Integer(1)
+ V_i = Integer(1)
+ U_temp = Integer(0)
+ V_temp = Integer(0)
+ # Step 6
+ for i in iter_range(r - 1, -1, -1):
+ # Square
+ # U_temp = U_i * V_i % candidate
+ U_temp.set(U_i)
+ U_temp *= V_i
+ U_temp %= candidate
+ # V_temp = (((V_i ** 2 + (U_i ** 2 * D)) * K) >> 1) % candidate
+ V_temp.set(U_i)
+ V_temp *= U_i
+ V_temp *= D
+ V_temp.multiply_accumulate(V_i, V_i)
+ if V_temp.is_odd():
+ V_temp += candidate
+ V_temp >>= 1
+ V_temp %= candidate
+ # Multiply
+ if K.get_bit(i):
+ # U_i = (((U_temp + V_temp) * K) >> 1) % candidate
+ U_i.set(U_temp)
+ U_i += V_temp
+ if U_i.is_odd():
+ U_i += candidate
+ U_i >>= 1
+ U_i %= candidate
+ # V_i = (((V_temp + U_temp * D) * K) >> 1) % candidate
+ V_i.set(V_temp)
+ V_i.multiply_accumulate(U_temp, D)
+ if V_i.is_odd():
+ V_i += candidate
+ V_i >>= 1
+ V_i %= candidate
+ else:
+ U_i.set(U_temp)
+ V_i.set(V_temp)
+ # Step 7
+ if U_i == 0:
+ return PROBABLY_PRIME
+ return COMPOSITE
+
+
+from Cryptodome.Util.number import sieve_base as _sieve_base_large
+## The optimal number of small primes to use for the sieve
+## is probably dependent on the platform and the candidate size
+_sieve_base = set(_sieve_base_large[:100])
+
+
+def test_probable_prime(candidate, randfunc=None):
+ """Test if a number is prime.
+
+ A number is qualified as prime if it passes a certain
+ number of Miller-Rabin tests (dependent on the size
+ of the number, but such that probability of a false
+ positive is less than 10^-30) and a single Lucas test.
+
+ For instance, a 1024-bit candidate will need to pass
+ 4 Miller-Rabin tests.
+
+ :Parameters:
+ candidate : integer
+ The number to test for primality.
+ randfunc : callable
+ The routine to draw random bytes from to select Miller-Rabin bases.
+ :Returns:
+ ``PROBABLE_PRIME`` if the number if prime with very high probability.
+ ``COMPOSITE`` if the number is a composite.
+ For efficiency reasons, ``COMPOSITE`` is also returned for small primes.
+ """
+
+ if randfunc is None:
+ randfunc = Random.new().read
+
+ if not isinstance(candidate, Integer):
+ candidate = Integer(candidate)
+
+ # First, check trial division by the smallest primes
+ if int(candidate) in _sieve_base:
+ return PROBABLY_PRIME
+ try:
+ map(candidate.fail_if_divisible_by, _sieve_base)
+ except ValueError:
+ return COMPOSITE
+
+ # These are the number of Miller-Rabin iterations s.t. p(k, t) < 1E-30,
+ # with p(k, t) being the probability that a randomly chosen k-bit number
+ # is composite but still survives t MR iterations.
+ mr_ranges = ((220, 30), (280, 20), (390, 15), (512, 10),
+ (620, 7), (740, 6), (890, 5), (1200, 4),
+ (1700, 3), (3700, 2))
+
+ bit_size = candidate.size_in_bits()
+ try:
+ mr_iterations = list(filter(lambda x: bit_size < x[0],
+ mr_ranges))[0][1]
+ except IndexError:
+ mr_iterations = 1
+
+ if miller_rabin_test(candidate, mr_iterations,
+ randfunc=randfunc) == COMPOSITE:
+ return COMPOSITE
+ if lucas_test(candidate) == COMPOSITE:
+ return COMPOSITE
+ return PROBABLY_PRIME
+
+
+def generate_probable_prime(**kwargs):
+ """Generate a random probable prime.
+
+ The prime will not have any specific properties
+ (e.g. it will not be a *strong* prime).
+
+ Random numbers are evaluated for primality until one
+ passes all tests, consisting of a certain number of
+ Miller-Rabin tests with random bases followed by
+ a single Lucas test.
+
+ The number of Miller-Rabin iterations is chosen such that
+ the probability that the output number is a non-prime is
+ less than 1E-30 (roughly 2^{-100}).
+
+ This approach is compliant to `FIPS PUB 186-4`__.
+
+ :Keywords:
+ exact_bits : integer
+ The desired size in bits of the probable prime.
+ It must be at least 160.
+ randfunc : callable
+ An RNG function where candidate primes are taken from.
+ prime_filter : callable
+ A function that takes an Integer as parameter and returns
+ True if the number can be passed to further primality tests,
+ False if it should be immediately discarded.
+
+ :Return:
+ A probable prime in the range 2^exact_bits > p > 2^(exact_bits-1).
+
+ .. __: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
+ """
+
+ exact_bits = kwargs.pop("exact_bits", None)
+ randfunc = kwargs.pop("randfunc", None)
+ prime_filter = kwargs.pop("prime_filter", lambda x: True)
+ if kwargs:
+ raise ValueError("Unknown parameters: " + kwargs.keys())
+
+ if exact_bits is None:
+ raise ValueError("Missing exact_bits parameter")
+ if exact_bits < 160:
+ raise ValueError("Prime number is not big enough.")
+
+ if randfunc is None:
+ randfunc = Random.new().read
+
+ result = COMPOSITE
+ while result == COMPOSITE:
+ candidate = Integer.random(exact_bits=exact_bits,
+ randfunc=randfunc) | 1
+ if not prime_filter(candidate):
+ continue
+ result = test_probable_prime(candidate, randfunc)
+ return candidate
+
+
+def generate_probable_safe_prime(**kwargs):
+ """Generate a random, probable safe prime.
+
+ Note this operation is much slower than generating a simple prime.
+
+ :Keywords:
+ exact_bits : integer
+ The desired size in bits of the probable safe prime.
+ randfunc : callable
+ An RNG function where candidate primes are taken from.
+
+ :Return:
+ A probable safe prime in the range
+ 2^exact_bits > p > 2^(exact_bits-1).
+ """
+
+ exact_bits = kwargs.pop("exact_bits", None)
+ randfunc = kwargs.pop("randfunc", None)
+ if kwargs:
+ raise ValueError("Unknown parameters: " + kwargs.keys())
+
+ if randfunc is None:
+ randfunc = Random.new().read
+
+ result = COMPOSITE
+ while result == COMPOSITE:
+ q = generate_probable_prime(exact_bits=exact_bits - 1, randfunc=randfunc)
+ candidate = q * 2 + 1
+ if candidate.size_in_bits() != exact_bits:
+ continue
+ result = test_probable_prime(candidate, randfunc=randfunc)
+ return candidate
diff --git a/frozen_deps/Cryptodome/Math/Primality.pyi b/frozen_deps/Cryptodome/Math/Primality.pyi
new file mode 100644
index 0000000..7813483
--- /dev/null
+++ b/frozen_deps/Cryptodome/Math/Primality.pyi
@@ -0,0 +1,18 @@
+from typing import Callable, Optional, Union, Set
+
+PrimeResult = int
+
+COMPOSITE: PrimeResult
+PROBABLY_PRIME: PrimeResult
+
+def miller_rabin_test(candidate: int, iterations: int, randfunc: Optional[Callable[[int],bytes]]=None) -> PrimeResult: ...
+def lucas_test(candidate: int) -> PrimeResult: ...
+_sieve_base: Set[int]
+def test_probable_prime(candidate: int, randfunc: Optional[Callable[[int],bytes]]=None) -> PrimeResult: ...
+def generate_probable_prime(*,
+ exact_bits: int = ...,
+ randfunc: Callable[[int],bytes] = ...,
+ prime_filter: Callable[[int],bool] = ...) -> int: ...
+def generate_probable_safe_prime(*,
+ exact_bits: int = ...,
+ randfunc: Callable[[int],bytes] = ...) -> int: ...
diff --git a/frozen_deps/Cryptodome/Math/_IntegerBase.py b/frozen_deps/Cryptodome/Math/_IntegerBase.py
new file mode 100644
index 0000000..f8cf333
--- /dev/null
+++ b/frozen_deps/Cryptodome/Math/_IntegerBase.py
@@ -0,0 +1,392 @@
+# ===================================================================
+#
+# 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 Cryptodome.Util.py3compat import iter_range, bord, bchr, ABC
+
+from Cryptodome import Random
+
+
+class IntegerBase(ABC):
+
+ # Conversions
+ @abc.abstractmethod
+ def __int__(self):
+ pass
+
+ @abc.abstractmethod
+ def __str__(self):
+ pass
+
+ @abc.abstractmethod
+ def __repr__(self):
+ pass
+
+ @abc.abstractmethod
+ def to_bytes(self, block_size=0):
+ pass
+
+ @staticmethod
+ @abc.abstractmethod
+ def from_bytes(byte_string):
+ pass
+
+ # Relations
+ @abc.abstractmethod
+ def __eq__(self, term):
+ pass
+
+ @abc.abstractmethod
+ def __ne__(self, term):
+ pass
+
+ @abc.abstractmethod
+ def __lt__(self, term):
+ pass
+
+ @abc.abstractmethod
+ def __le__(self, term):
+ pass
+
+ @abc.abstractmethod
+ def __gt__(self, term):
+ pass
+
+ @abc.abstractmethod
+ def __ge__(self, term):
+ pass
+
+ @abc.abstractmethod
+ def __nonzero__(self):
+ pass
+ __bool__ = __nonzero__
+
+ @abc.abstractmethod
+ def is_negative(self):
+ pass
+
+ # Arithmetic operations
+ @abc.abstractmethod
+ def __add__(self, term):
+ pass
+
+ @abc.abstractmethod
+ def __sub__(self, term):
+ pass
+
+ @abc.abstractmethod
+ def __mul__(self, factor):
+ pass
+
+ @abc.abstractmethod
+ def __floordiv__(self, divisor):
+ pass
+
+ @abc.abstractmethod
+ def __mod__(self, divisor):
+ pass
+
+ @abc.abstractmethod
+ def inplace_pow(self, exponent, modulus=None):
+ pass
+
+ @abc.abstractmethod
+ def __pow__(self, exponent, modulus=None):
+ pass
+
+ @abc.abstractmethod
+ def __abs__(self):
+ pass
+
+ @abc.abstractmethod
+ def sqrt(self, modulus=None):
+ pass
+
+ @abc.abstractmethod
+ def __iadd__(self, term):
+ pass
+
+ @abc.abstractmethod
+ def __isub__(self, term):
+ pass
+
+ @abc.abstractmethod
+ def __imul__(self, term):
+ pass
+
+ @abc.abstractmethod
+ def __imod__(self, term):
+ pass
+
+ # Boolean/bit operations
+ @abc.abstractmethod
+ def __and__(self, term):
+ pass
+
+ @abc.abstractmethod
+ def __or__(self, term):
+ pass
+
+ @abc.abstractmethod
+ def __rshift__(self, pos):
+ pass
+
+ @abc.abstractmethod
+ def __irshift__(self, pos):
+ pass
+
+ @abc.abstractmethod
+ def __lshift__(self, pos):
+ pass
+
+ @abc.abstractmethod
+ def __ilshift__(self, pos):
+ pass
+
+ @abc.abstractmethod
+ def get_bit(self, n):
+ pass
+
+ # Extra
+ @abc.abstractmethod
+ def is_odd(self):
+ pass
+
+ @abc.abstractmethod
+ def is_even(self):
+ pass
+
+ @abc.abstractmethod
+ def size_in_bits(self):
+ pass
+
+ @abc.abstractmethod
+ def size_in_bytes(self):
+ pass
+
+ @abc.abstractmethod
+ def is_perfect_square(self):
+ pass
+
+ @abc.abstractmethod
+ def fail_if_divisible_by(self, small_prime):
+ pass
+
+ @abc.abstractmethod
+ def multiply_accumulate(self, a, b):
+ pass
+
+ @abc.abstractmethod
+ def set(self, source):
+ pass
+
+ @abc.abstractmethod
+ def inplace_inverse(self, modulus):
+ pass
+
+ @abc.abstractmethod
+ def inverse(self, modulus):
+ pass
+
+ @abc.abstractmethod
+ def gcd(self, term):
+ pass
+
+ @abc.abstractmethod
+ def lcm(self, term):
+ pass
+
+ @staticmethod
+ @abc.abstractmethod
+ def jacobi_symbol(a, n):
+ pass
+
+ @staticmethod
+ 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
+
+ @classmethod
+ 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))
+
+ @classmethod
+ 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
+
diff --git a/frozen_deps/Cryptodome/Math/_IntegerBase.pyi b/frozen_deps/Cryptodome/Math/_IntegerBase.pyi
new file mode 100644
index 0000000..3f534db
--- /dev/null
+++ b/frozen_deps/Cryptodome/Math/_IntegerBase.pyi
@@ -0,0 +1,61 @@
+from typing import Optional, Union, Callable
+
+RandFunc = Callable[[int],int]
+
+class IntegerBase:
+
+ def __int__(self) -> int: ...
+ def __str__(self) -> str: ...
+ def __repr__(self) -> str: ...
+ def to_bytes(self, block_size: Optional[int]=0) -> bytes: ...
+ @staticmethod
+ def from_bytes(byte_string: bytes) -> IntegerBase: ...
+ def __eq__(self, term: object) -> bool: ...
+ def __ne__(self, term: object) -> bool: ...
+ def __lt__(self, term: Union[IntegerBase, int]) -> bool: ...
+ def __le__(self, term: Union[IntegerBase, int]) -> bool: ...
+ def __gt__(self, term: Union[IntegerBase, int]) -> bool: ...
+ def __ge__(self, term: Union[IntegerBase, int]) -> bool: ...
+ def __nonzero__(self) -> bool: ...
+ def is_negative(self) -> bool: ...
+ def __add__(self, term: Union[IntegerBase, int]) -> IntegerBase: ...
+ def __sub__(self, term: Union[IntegerBase, int]) -> IntegerBase: ...
+ def __mul__(self, term: Union[IntegerBase, int]) -> IntegerBase: ...
+ def __floordiv__(self, divisor: Union[IntegerBase, int]) -> IntegerBase: ...
+ def __mod__(self, divisor: Union[IntegerBase, int]) -> IntegerBase: ...
+ def inplace_pow(self, exponent: int, modulus: Optional[Union[IntegerBase, int]]=None) -> IntegerBase: ...
+ def __pow__(self, exponent: int, modulus: Optional[int]) -> IntegerBase: ...
+ def __abs__(self) -> IntegerBase: ...
+ def sqrt(self, modulus: Optional[int]) -> IntegerBase: ...
+ def __iadd__(self, term: Union[IntegerBase, int]) -> IntegerBase: ...
+ def __isub__(self, term: Union[IntegerBase, int]) -> IntegerBase: ...
+ def __imul__(self, term: Union[IntegerBase, int]) -> IntegerBase: ...
+ def __imod__(self, divisor: Union[IntegerBase, int]) -> IntegerBase: ...
+ def __and__(self, term: Union[IntegerBase, int]) -> IntegerBase: ...
+ def __or__(self, term: Union[IntegerBase, int]) -> IntegerBase: ...
+ def __rshift__(self, pos: Union[IntegerBase, int]) -> IntegerBase: ...
+ def __irshift__(self, pos: Union[IntegerBase, int]) -> IntegerBase: ...
+ def __lshift__(self, pos: Union[IntegerBase, int]) -> IntegerBase: ...
+ def __ilshift__(self, pos: Union[IntegerBase, int]) -> IntegerBase: ...
+ def get_bit(self, n: int) -> bool: ...
+ def is_odd(self) -> bool: ...
+ def is_even(self) -> bool: ...
+ def size_in_bits(self) -> int: ...
+ def size_in_bytes(self) -> int: ...
+ def is_perfect_square(self) -> bool: ...
+ def fail_if_divisible_by(self, small_prime: Union[IntegerBase, int]) -> None: ...
+ def multiply_accumulate(self, a: Union[IntegerBase, int], b: Union[IntegerBase, int]) -> IntegerBase: ...
+ def set(self, source: Union[IntegerBase, int]) -> IntegerBase: ...
+ def inplace_inverse(self, modulus: Union[IntegerBase, int]) -> IntegerBase: ...
+ def inverse(self, modulus: Union[IntegerBase, int]) -> IntegerBase: ...
+ def gcd(self, term: Union[IntegerBase, int]) -> IntegerBase: ...
+ def lcm(self, term: Union[IntegerBase, int]) -> IntegerBase: ...
+ @staticmethod
+ def jacobi_symbol(a: Union[IntegerBase, int], n: Union[IntegerBase, int]) -> IntegerBase: ...
+ @staticmethod
+ def _tonelli_shanks(n: Union[IntegerBase, int], p: Union[IntegerBase, int]) -> IntegerBase : ...
+ @classmethod
+ def random(cls, **kwargs: Union[int,RandFunc]) -> IntegerBase : ...
+ @classmethod
+ def random_range(cls, **kwargs: Union[int,RandFunc]) -> IntegerBase : ...
+
diff --git a/frozen_deps/Cryptodome/Math/_IntegerCustom.py b/frozen_deps/Cryptodome/Math/_IntegerCustom.py
new file mode 100644
index 0000000..b626014
--- /dev/null
+++ b/frozen_deps/Cryptodome/Math/_IntegerCustom.py
@@ -0,0 +1,111 @@
+# ===================================================================
+#
+# 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.