diff --git a/cryptography/__init__.py b/cryptography/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/cryptography/shor_algorithm.py b/cryptography/shor_algorithm.py new file mode 100644 index 000000000000..110d3278b40d --- /dev/null +++ b/cryptography/shor_algorithm.py @@ -0,0 +1,99 @@ +""" +Classical simulation of Shor's Algorithm to factor integers. + +Source: https://en.wikipedia.org/wiki/Shor%27s_algorithm +""" + +import math +import random +from typing import Any + + +def is_prime(n: int) -> bool: + """ + Check if a number is prime. + + >>> is_prime(2) + True + >>> is_prime(4) + False + """ + if n < 2: + return False + if n in (2, 3): + return True + if n % 2 == 0: + return False + r = math.isqrt(n) + return all(n % i != 0 for i in range(3, r + 1, 2)) + + +def modexp(a: int, b: int, m: int) -> int: + """ + Modular exponentiation: (a^b) % m + + >>> modexp(2, 5, 13) + 6 + """ + result = 1 + a = a % m + while b > 0: + if b & 1: + result = (result * a) % m + a = (a * a) % m + b >>= 1 + return result + + +def shor_classical(n: int, max_attempts: int = 10) -> str | tuple[int, int]: + """ + Classical approximation of Shor's Algorithm to factor a number. + + >>> result = shor_classical(15) + >>> isinstance(result, tuple) + True + >>> sorted(result) == [3, 5] + True + + >>> shor_classical(13) # Prime + 'No factors: 13 is prime' + """ + if n <= 1: + return "Failure: input must be > 1" + if n % 2 == 0: + return 2, n // 2 + if is_prime(n): + return f"No factors: {n} is prime" + + for _ in range(max_attempts): + a = random.randrange(2, n - 1) + g = math.gcd(a, n) + if g > 1: + return g, n // g + + r = 1 + while r < n: + if modexp(a, r, n) == 1: + break + r += 1 + else: + continue + + if r % 2 != 0: + continue + x = modexp(a, r // 2, n) + if x == n - 1: + continue + + factor1 = math.gcd(x - 1, n) + factor2 = math.gcd(x + 1, n) + if factor1 not in (1, n) and factor2 not in (1, n): + return factor1, factor2 + + return "Failure: try more attempts" + + +if __name__ == "__main__": + import doctest + + doctest.testmod() diff --git a/cryptography/tests/__init__.py b/cryptography/tests/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/cryptography/tests/test_shor_algorithm.py b/cryptography/tests/test_shor_algorithm.py new file mode 100644 index 000000000000..6c12e748a2a2 --- /dev/null +++ b/cryptography/tests/test_shor_algorithm.py @@ -0,0 +1,36 @@ +import pytest +from cryptography.shor_algorithm import shor_classical + + +def test_small_composite(): + factors = shor_classical(15) + assert set(factors) == {3, 5} + + +def test_medium_composite(): + factors = shor_classical(21) + assert set(factors) == {3, 7} + + +def test_even_number(): + factors = shor_classical(18) + assert set(factors) == {2, 9} + + +def test_prime_number(): + result = shor_classical(13) + assert isinstance(result, str) + assert "prime" in result.lower() + + +def test_invalid_input(): + result = shor_classical(1) + assert isinstance(result, str) + assert "failure" in result.lower() + + +def test_larger_composite_number(): + result = shor_classical(91) + assert isinstance(result, (tuple, str)) + if isinstance(result, tuple): + assert all(isinstance(x, int) for x in result)
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: