From 13d33f3b3ba78a71e87859a01de1be6b4f110d7d Mon Sep 17 00:00:00 2001 From: Pranav Lawate Date: Sun, 5 Oct 2025 14:39:01 +0530 Subject: [PATCH] Add comprehensive doctests to find_mod_inverse function - Added detailed docstring explaining modular multiplicative inverse - Included 10 valid test cases with verification calculations - Added 3 error cases testing ValueError for non-coprime inputs - Added Wikipedia reference for educational value - All doctests pass locally (python -m doctest -v) - Passes ruff, mypy, and pre-commit hooks Contributes to #9943 --- ciphers/cryptomath_module.py | 56 ++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/ciphers/cryptomath_module.py b/ciphers/cryptomath_module.py index 02e94e4b9e92..78df4bb27fd3 100644 --- a/ciphers/cryptomath_module.py +++ b/ciphers/cryptomath_module.py @@ -2,6 +2,62 @@ def find_mod_inverse(a: int, m: int) -> int: + """ + Find the modular multiplicative inverse of a modulo m. + + The modular multiplicative inverse of a modulo m is an integer x such that: + (a * x) % m = 1 + + This function uses the Extended Euclidean Algorithm to find the inverse. + An inverse exists if and only if a and m are coprime (gcd(a, m) = 1). + + Args: + a: The integer to find the inverse of + m: The modulus + + Returns: + The modular multiplicative inverse of a modulo m + + Raises: + ValueError: If gcd(a, m) != 1 (inverse does not exist) + + Reference: + https://en.wikipedia.org/wiki/Modular_multiplicative_inverse + + Examples: + >>> find_mod_inverse(3, 7) + 5 + >>> (3 * 5) % 7 # Verify: 3 * 5 ≡ 1 (mod 7) + 1 + >>> find_mod_inverse(3, 10) + 7 + >>> (3 * 7) % 10 # Verify: 3 * 7 ≡ 1 (mod 10) + 1 + >>> find_mod_inverse(4, 11) + 3 + >>> (4 * 3) % 11 # Verify: 4 * 3 ≡ 1 (mod 11) + 1 + >>> find_mod_inverse(7, 26) + 15 + >>> (7 * 15) % 26 # Verify: 7 * 15 ≡ 1 (mod 26) + 1 + >>> find_mod_inverse(1, 5) + 1 + >>> find_mod_inverse(5, 11) + 9 + >>> find_mod_inverse(2, 4) + Traceback (most recent call last): + ... + ValueError: mod inverse of 2 and 4 does not exist + >>> find_mod_inverse(6, 9) + Traceback (most recent call last): + ... + ValueError: mod inverse of 6 and 9 does not exist + >>> find_mod_inverse(10, 20) + Traceback (most recent call last): + ... + ValueError: mod inverse of 10 and 20 does not exist + """ if gcd_by_iterative(a, m) != 1: msg = f"mod inverse of {a!r} and {m!r} does not exist" raise ValueError(msg)