From 77042d581f1963484c0099b8011391b89671b3a6 Mon Sep 17 00:00:00 2001 From: saahil-mahato Date: Thu, 12 Oct 2023 23:48:02 +0545 Subject: [PATCH 1/3] Add Solovay-Strassen Primality test --- maths/solovay_strassen_primality_test.py | 105 +++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 maths/solovay_strassen_primality_test.py diff --git a/maths/solovay_strassen_primality_test.py b/maths/solovay_strassen_primality_test.py new file mode 100644 index 000000000000..ac5beb66b2e3 --- /dev/null +++ b/maths/solovay_strassen_primality_test.py @@ -0,0 +1,105 @@ +""" +This script implements the Solovay-Strassen Primality test. + +This probabilistic primality test is based on Euler's criterion. It is similar +to the Fermat test but uses quadratic residues. It can quickly identify +composite numbers but may occasionally classify composite numbers as prime. + +More details and concepts about this can be found on: +https://en.wikipedia.org/wiki/Solovay%E2%80%93Strassen_primality_test +""" + + +import random + + +def jacobi_symbol(random_a: int, number: int) -> int: + """ + Calculate the Jacobi symbol. The Jacobi symbol is a mathematical function + used to determine whether an integer is a quadratic residue modulo + another integer (usually prime) or not. + + Parameters: + random_a (int): A randomly chosen integer from 2 to n-2 (inclusive) + number (int): The number that is tested for primality + + Returns: + jocobi_symbol (int): The jacobi symbol + + >>> jacobi_symbol(2, 13) + -1 + >>> jacobi_symbol(5, 19) + 1 + >>> jacobi_symbol(7, 14) + 0 + """ + + if random_a == 0: + return 0 + if random_a == 1: + return 1 + + random_a = random_a % number + t = 1 + + while random_a != 0: + while random_a % 2 == 0: + random_a = random_a // 2 + r = number % 8 + if r in (3, 5): + t = -t + + random_a, number = number, random_a + + if random_a % 4 == number % 4 == 3: + t = -t + + random_a = random_a % number + + if number == 1: + return t + else: + return 0 + + +def solovay_strassen(number: int, accuracy: int) -> bool: + """ + Check whether the input number is prime or not using + the Solovay-Strassen Primality test + + Parameters: + number (int): The number that is tested for primality + accuracy (int): The accuracy for the test + + Returns: + result (bool): True if number is probably prime and false + if composite + + >>> solovay_strassen(13, 5) + True + >>> solovay_strassen(9, 10) + False + >>> solovay_strassen(17, 15) + True + """ + + if number <= 1: + return False + if number <= 3: + return True + + for _ in range(accuracy): + a = random.randint(2, number - 2) + x = jacobi_symbol(a, number) + y = pow(a, (number - 1) // 2, number) + + if x == 0 or y != x % number: + return False + + return True + + +if __name__ == "__main__": + import doctest + + doctest.testmod() From d78ce88d562561a8a112ccb1a05c1446c49b3946 Mon Sep 17 00:00:00 2001 From: saahil-mahato Date: Fri, 13 Oct 2023 10:41:44 +0545 Subject: [PATCH 2/3] fix: resolve comments --- maths/solovay_strassen_primality_test.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/maths/solovay_strassen_primality_test.py b/maths/solovay_strassen_primality_test.py index ac5beb66b2e3..7349fbf6dd37 100644 --- a/maths/solovay_strassen_primality_test.py +++ b/maths/solovay_strassen_primality_test.py @@ -24,7 +24,7 @@ def jacobi_symbol(random_a: int, number: int) -> int: number (int): The number that is tested for primality Returns: - jocobi_symbol (int): The jacobi symbol + jacobi_symbol (int): The Jacobi symbol >>> jacobi_symbol(2, 13) -1 @@ -39,12 +39,12 @@ def jacobi_symbol(random_a: int, number: int) -> int: if random_a == 1: return 1 - random_a = random_a % number + random_a %= number t = 1 while random_a != 0: while random_a % 2 == 0: - random_a = random_a // 2 + random_a //= 2 r = number % 8 if r in (3, 5): t = -t @@ -54,27 +54,25 @@ def jacobi_symbol(random_a: int, number: int) -> int: if random_a % 4 == number % 4 == 3: t = -t - random_a = random_a % number + random_a %= number - if number == 1: - return t - else: - return 0 + return t if number == 1 else 0 -def solovay_strassen(number: int, accuracy: int) -> bool: +def solovay_strassen(number: int, iterations: int) -> bool: """ Check whether the input number is prime or not using the Solovay-Strassen Primality test Parameters: number (int): The number that is tested for primality - accuracy (int): The accuracy for the test + iterations (int): The iterations/accuracy for the test Returns: result (bool): True if number is probably prime and false if composite + >>> random.seed(10) >>> solovay_strassen(13, 5) True >>> solovay_strassen(9, 10) @@ -88,7 +86,7 @@ def solovay_strassen(number: int, accuracy: int) -> bool: if number <= 3: return True - for _ in range(accuracy): + for _ in range(iterations): a = random.randint(2, number - 2) x = jacobi_symbol(a, number) y = pow(a, (number - 1) // 2, number) From 83542f177389f4de836d51101b66a77eddd11cc7 Mon Sep 17 00:00:00 2001 From: saahil-mahato Date: Fri, 13 Oct 2023 11:43:17 +0545 Subject: [PATCH 3/3] refactor: docs change --- maths/solovay_strassen_primality_test.py | 32 +++++++++++++----------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/maths/solovay_strassen_primality_test.py b/maths/solovay_strassen_primality_test.py index 7349fbf6dd37..1d11d458369a 100644 --- a/maths/solovay_strassen_primality_test.py +++ b/maths/solovay_strassen_primality_test.py @@ -15,16 +15,21 @@ def jacobi_symbol(random_a: int, number: int) -> int: """ - Calculate the Jacobi symbol. The Jacobi symbol is a mathematical function - used to determine whether an integer is a quadratic residue modulo - another integer (usually prime) or not. + Calculate the Jacobi symbol. The Jacobi symbol is a generalization + of the Legendre symbol, which can be used to simplify computations involving + quadratic residues. The Jacobi symbol is used in primality tests, like the + Solovay-Strassen test, because it helps determine if an integer is a + quadratic residue modulo a given modulus, providing valuable information + about the number's potential primality or compositeness. Parameters: - random_a (int): A randomly chosen integer from 2 to n-2 (inclusive) - number (int): The number that is tested for primality + random_a: A randomly chosen integer from 2 to n-2 (inclusive) + number: The number that is tested for primality Returns: - jacobi_symbol (int): The Jacobi symbol + jacobi_symbol: The Jacobi symbol is a mathematical function + used to determine whether an integer is a quadratic residue modulo + another integer (usually prime) or not. >>> jacobi_symbol(2, 13) -1 @@ -34,10 +39,8 @@ def jacobi_symbol(random_a: int, number: int) -> int: 0 """ - if random_a == 0: - return 0 - if random_a == 1: - return 1 + if random_a in (0, 1): + return random_a random_a %= number t = 1 @@ -65,12 +68,13 @@ def solovay_strassen(number: int, iterations: int) -> bool: the Solovay-Strassen Primality test Parameters: - number (int): The number that is tested for primality - iterations (int): The iterations/accuracy for the test + number: The number that is tested for primality + iterations: The number of times that the test is run + which effects the accuracy Returns: - result (bool): True if number is probably prime and false - if composite + result: True if number is probably prime and false + if not >>> random.seed(10) >>> solovay_strassen(13, 5)