Skip to content

Commit e958476

Browse files
[pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
1 parent 22bb965 commit e958476

File tree

2 files changed

+38
-37
lines changed

2 files changed

+38
-37
lines changed

maths/pollard_rho_discrete_log.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ def pollards_rho_discrete_log(g: int, h: int, p: int) -> Optional[int]:
99
using Pollard's Rho algorithm.
1010
1111
This is a probabilistic algorithm that finds discrete logarithms in O(√p) time.
12-
The algorithm may not always find a solution in a single run due to its
12+
The algorithm may not always find a solution in a single run due to its
1313
probabilistic nature, but it will find the correct answer when it succeeds.
1414
1515
Parameters
@@ -31,15 +31,15 @@ def pollards_rho_discrete_log(g: int, h: int, p: int) -> Optional[int]:
3131
>>> result = pollards_rho_discrete_log(2, 22, 29)
3232
>>> result is not None and pow(2, result, 29) == 22
3333
True
34-
34+
3535
>>> result = pollards_rho_discrete_log(3, 9, 11)
3636
>>> result is not None and pow(3, result, 11) == 9
3737
True
38-
38+
3939
>>> result = pollards_rho_discrete_log(5, 3, 7)
4040
>>> result is not None and pow(5, result, 7) == 3
4141
True
42-
42+
4343
>>> # Case with no solution should return None or fail verification
4444
>>> result = pollards_rho_discrete_log(3, 7, 11)
4545
>>> result is None or pow(3, result, 11) != 7
@@ -60,21 +60,21 @@ def f(x, a, b):
6060

6161
# Try multiple random starting points to avoid immediate collisions
6262
max_attempts = 50 # Increased attempts for better reliability
63-
63+
6464
for attempt in range(max_attempts):
6565
# Use different starting values to avoid trivial collisions
6666
# x represents g^a * h^b
6767
random.seed() # Ensure truly random values
6868
a = random.randint(0, p - 2)
6969
b = random.randint(0, p - 2)
70-
70+
7171
# Ensure x = g^a * h^b mod p
7272
x = (pow(g, a, p) * pow(h, b, p)) % p
73-
73+
7474
# Skip if x is 0 or 1 (problematic starting points)
7575
if x <= 1:
7676
continue
77-
77+
7878
X, A, B = x, a, b # Tortoise and hare start at same position
7979

8080
# Increased iteration limit for better coverage
@@ -100,21 +100,21 @@ def f(x, a, b):
100100
break # No inverse, try different starting point
101101

102102
x_log = (r * inv_s) % (p - 1)
103-
103+
104104
# Verify the solution
105105
if pow(g, x_log, p) == h:
106106
return x_log
107107
break # This attempt failed, try with different starting point
108-
108+
109109
return None
110110

111111

112112
if __name__ == "__main__":
113113
import doctest
114-
114+
115115
# Run doctests
116116
doctest.testmod(verbose=True)
117-
117+
118118
# Also run the main example
119119
result = pollards_rho_discrete_log(2, 22, 29)
120120
print(f"pollards_rho_discrete_log(2, 22, 29) = {result}")

maths/test_pollard_rho_discrete_log.py

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,19 @@ def test_basic_example(self):
2929
self.assertEqual(pow(2, result, 29), 22)
3030
found_solution = True
3131
break
32-
33-
self.assertTrue(found_solution,
34-
"Algorithm should find a solution within 5 attempts")
32+
33+
self.assertTrue(
34+
found_solution, "Algorithm should find a solution within 5 attempts"
35+
)
3536

3637
def test_simple_cases(self):
3738
"""Test simple discrete log cases with known answers."""
3839
test_cases = [
39-
(2, 8, 17), # 2^3 ≡ 8 (mod 17)
40-
(5, 3, 7), # 5^5 ≡ 3 (mod 7)
41-
(3, 9, 11), # 3^2 ≡ 9 (mod 11)
40+
(2, 8, 17), # 2^3 ≡ 8 (mod 17)
41+
(5, 3, 7), # 5^5 ≡ 3 (mod 7)
42+
(3, 9, 11), # 3^2 ≡ 9 (mod 11)
4243
]
43-
44+
4445
for g, h, p in test_cases:
4546
# Try multiple times due to probabilistic nature
4647
found_solution = False
@@ -56,8 +57,7 @@ def test_no_solution_case(self):
5657
"""Test case where no solution exists."""
5758
# 3^x ≡ 7 (mod 11) has no solution (verified by brute force)
5859
# The algorithm should return None or fail to find a solution
59-
result = pollards_rho_discrete_log(3, 7, 11)
60-
if result is not None:
60+
if (result := pollards_rho_discrete_log(3, 7, 11)) is not None:
6161
# If it returns a result, it must be wrong since no solution exists
6262
self.assertNotEqual(pow(3, result, 11), 7)
6363

@@ -67,7 +67,7 @@ def test_edge_cases(self):
6767
result = pollards_rho_discrete_log(1, 1, 7)
6868
if result is not None:
6969
self.assertEqual(pow(1, result, 7), 1)
70-
70+
7171
# h = 1: g^x ≡ 1 (mod p) - looking for the multiplicative order
7272
result = pollards_rho_discrete_log(3, 1, 7)
7373
if result is not None:
@@ -76,27 +76,27 @@ def test_edge_cases(self):
7676
def test_small_primes(self):
7777
"""Test with small prime moduli."""
7878
test_cases = [
79-
(2, 4, 5), # 2^2 ≡ 4 (mod 5)
80-
(2, 3, 5), # 2^? ≡ 3 (mod 5)
81-
(2, 1, 3), # 2^2 ≡ 1 (mod 3)
82-
(3, 2, 5), # 3^3 ≡ 2 (mod 5)
79+
(2, 4, 5), # 2^2 ≡ 4 (mod 5)
80+
(2, 3, 5), # 2^? ≡ 3 (mod 5)
81+
(2, 1, 3), # 2^2 ≡ 1 (mod 3)
82+
(3, 2, 5), # 3^3 ≡ 2 (mod 5)
8383
]
84-
84+
8585
for g, h, p in test_cases:
8686
result = pollards_rho_discrete_log(g, h, p)
8787
if result is not None:
8888
# Verify the result is mathematically correct
8989
self.assertEqual(pow(g, result, p), h)
90-
90+
9191
def test_larger_examples(self):
9292
"""Test with larger numbers to ensure algorithm scales."""
9393
# Test cases with larger primes
9494
test_cases = [
95-
(2, 15, 31), # Find x where 2^x ≡ 15 (mod 31)
96-
(3, 10, 37), # Find x where 3^x ≡ 10 (mod 37)
97-
(5, 17, 41), # Find x where 5^x ≡ 17 (mod 41)
95+
(2, 15, 31), # Find x where 2^x ≡ 15 (mod 31)
96+
(3, 10, 37), # Find x where 3^x ≡ 10 (mod 37)
97+
(5, 17, 41), # Find x where 5^x ≡ 17 (mod 41)
9898
]
99-
99+
100100
for g, h, p in test_cases:
101101
result = pollards_rho_discrete_log(g, h, p)
102102
if result is not None:
@@ -108,17 +108,18 @@ def test_multiple_runs_consistency(self):
108108
# and ensure any returned result is mathematically correct
109109
g, h, p = 2, 22, 29
110110
results = []
111-
111+
112112
for _ in range(10): # Run 10 times
113113
result = pollards_rho_discrete_log(g, h, p)
114114
if result is not None:
115115
results.append(result)
116116
self.assertEqual(pow(g, result, p), h)
117-
117+
118118
# Should find at least one solution in 10 attempts
119-
self.assertGreater(len(results), 0,
120-
"Algorithm should find solution in multiple attempts")
119+
self.assertGreater(
120+
len(results), 0, "Algorithm should find solution in multiple attempts"
121+
)
121122

122123

123124
if __name__ == "__main__":
124-
unittest.main(verbosity=2)
125+
unittest.main(verbosity=2)

0 commit comments

Comments
 (0)