about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/rsa/common.py
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/rsa/common.py')
-rw-r--r--.venv/lib/python3.12/site-packages/rsa/common.py184
1 files changed, 184 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/rsa/common.py b/.venv/lib/python3.12/site-packages/rsa/common.py
new file mode 100644
index 00000000..520dfec6
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/rsa/common.py
@@ -0,0 +1,184 @@
+#  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.

+

+"""Common functionality shared by several modules."""

+

+import typing

+

+

+class NotRelativePrimeError(ValueError):

+    def __init__(self, a: int, b: int, d: int, msg: str = "") -> None:

+        super().__init__(msg or "%d and %d are not relatively prime, divider=%i" % (a, b, d))

+        self.a = a

+        self.b = b

+        self.d = d

+

+

+def bit_size(num: int) -> int:

+    """

+    Number of bits needed to represent a integer excluding any prefix

+    0 bits.

+

+    Usage::

+

+        >>> bit_size(1023)

+        10

+        >>> bit_size(1024)

+        11

+        >>> bit_size(1025)

+        11

+

+    :param num:

+        Integer value. If num is 0, returns 0. Only the absolute value of the

+        number is considered. Therefore, signed integers will be abs(num)

+        before the number's bit length is determined.

+    :returns:

+        Returns the number of bits in the integer.

+    """

+

+    try:

+        return num.bit_length()

+    except AttributeError as ex:

+        raise TypeError("bit_size(num) only supports integers, not %r" % type(num)) from ex

+

+

+def byte_size(number: int) -> int:

+    """

+    Returns the number of bytes required to hold a specific long number.

+

+    The number of bytes is rounded up.

+

+    Usage::

+

+        >>> byte_size(1 << 1023)

+        128

+        >>> byte_size((1 << 1024) - 1)

+        128

+        >>> byte_size(1 << 1024)

+        129

+

+    :param number:

+        An unsigned integer

+    :returns:

+        The number of bytes required to hold a specific long number.

+    """

+    if number == 0:

+        return 1

+    return ceil_div(bit_size(number), 8)

+

+

+def ceil_div(num: int, div: int) -> int:

+    """

+    Returns the ceiling function of a division between `num` and `div`.

+

+    Usage::

+

+        >>> ceil_div(100, 7)

+        15

+        >>> ceil_div(100, 10)

+        10

+        >>> ceil_div(1, 4)

+        1

+

+    :param num: Division's numerator, a number

+    :param div: Division's divisor, a number

+

+    :return: Rounded up result of the division between the parameters.

+    """

+    quanta, mod = divmod(num, div)

+    if mod:

+        quanta += 1

+    return quanta

+

+

+def extended_gcd(a: int, b: int) -> typing.Tuple[int, int, int]:

+    """Returns a tuple (r, i, j) such that r = gcd(a, b) = ia + jb"""

+    # r = gcd(a,b) i = multiplicitive inverse of a mod b

+    #      or      j = multiplicitive inverse of b mod a

+    # Neg return values for i or j are made positive mod b or a respectively

+    # Iterateive Version is faster and uses much less stack space

+    x = 0

+    y = 1

+    lx = 1

+    ly = 0

+    oa = a  # Remember original a/b to remove

+    ob = b  # negative values from return results

+    while b != 0:

+        q = a // b

+        (a, b) = (b, a % b)

+        (x, lx) = ((lx - (q * x)), x)

+        (y, ly) = ((ly - (q * y)), y)

+    if lx < 0:

+        lx += ob  # If neg wrap modulo original b

+    if ly < 0:

+        ly += oa  # If neg wrap modulo original a

+    return a, lx, ly  # Return only positive values

+

+

+def inverse(x: int, n: int) -> int:

+    """Returns the inverse of x % n under multiplication, a.k.a x^-1 (mod n)

+

+    >>> inverse(7, 4)

+    3

+    >>> (inverse(143, 4) * 143) % 4

+    1

+    """

+

+    (divider, inv, _) = extended_gcd(x, n)

+

+    if divider != 1:

+        raise NotRelativePrimeError(x, n, divider)

+

+    return inv

+

+

+def crt(a_values: typing.Iterable[int], modulo_values: typing.Iterable[int]) -> int:

+    """Chinese Remainder Theorem.

+

+    Calculates x such that x = a[i] (mod m[i]) for each i.

+

+    :param a_values: the a-values of the above equation

+    :param modulo_values: the m-values of the above equation

+    :returns: x such that x = a[i] (mod m[i]) for each i

+

+

+    >>> crt([2, 3], [3, 5])

+    8

+

+    >>> crt([2, 3, 2], [3, 5, 7])

+    23

+

+    >>> crt([2, 3, 0], [7, 11, 15])

+    135

+    """

+

+    m = 1

+    x = 0

+

+    for modulo in modulo_values:

+        m *= modulo

+

+    for (m_i, a_i) in zip(modulo_values, a_values):

+        M_i = m // m_i

+        inv = inverse(M_i, m_i)

+

+        x = (x + a_i * M_i * inv) % m

+

+    return x

+

+

+if __name__ == "__main__":

+    import doctest

+

+    doctest.testmod()