import sage.all as sage
from sage.groups.generic import order_from_multiple
class GroupOrderAlgorithms:
def __init__(self, p, generator=None):
self.p = sage.Integer(p)
self.Fp = sage.Integers(self.p)
if generator is None:
self.generator = self.find_generator()
else:
self.generator = self.Fp(generator)
self.order = self.p - 1
def find_generator(self):
for g in range(2, min(100, self.p)): if self.is_generator(g):
return self.Fp(g)
raise ValueError("No generator found")
def is_generator(self, g):
g = self.Fp(g)
if g == 1:
return False
p_minus_1 = self.p - 1
factors = p_minus_1.factor()
for q, _ in factors:
exponent = p_minus_1 // q
if g**exponent == 1:
return False
return True
def trial_division_order(self, g, max_iterations=10000):
g = self.Fp(g)
current = self.Fp(1)
order = 0
for i in range(1, max_iterations + 1):
current = current * g
if current == 1:
return i
return None
def pollard_rho_order(self, g, max_iterations=1000):
return self.order_from_factorization(g)
def order_from_factorization(self, g):
g = self.Fp(g)
p_minus_1 = self.p - 1
factors = p_minus_1.factor()
order = p_minus_1
for q, e in factors:
q_to_e = q**e
exponent = order // q_to_e
while exponent > 0 and g**exponent == 1:
order = order // q
exponent = order // q_to_e
return order
def compute_order(self, g, algorithm='factorization'):
if algorithm == 'trial':
return self.trial_division_order(g)
elif algorithm == 'pollard_rho':
return self.pollard_rho_order(g)
elif algorithm == 'factorization':
return self.order_from_factorization(g)
else:
raise ValueError(f"Unknown algorithm: {algorithm}")
def verify_order(self, g, order):
g = self.Fp(g)
order = sage.Integer(order)
return g**order == 1 and g**(order // 2) != 1
def find_element_of_order(self, target_order):
if (self.p - 1) % target_order != 0:
return None
g = self.generator
cofactor = (self.p - 1) // target_order
return g**cofactor
def test_order_computation(self):
print("Testing group order computation...")
g = self.generator
expected_order = self.p - 1
print(f"Testing order of generator g = {g}")
print(f"Expected order: {expected_order}")
try:
order_trial = self.trial_division_order(g, max_iterations=1000)
print(f"Trial division: {order_trial}")
print(f"Correct: {order_trial == expected_order}")
except Exception as e:
print(f"Trial division failed: {e}")
try:
order_factor = self.order_from_factorization(g)
print(f"Factorization: {order_factor}")
print(f"Correct: {order_factor == expected_order}")
except Exception as e:
print(f"Factorization failed: {e}")
if self.p > 100: p_minus_1_factors = (self.p - 1).factor()
if len(p_minus_1_factors) > 1:
small_order = p_minus_1_factors[0][0] h = self.find_element_of_order(small_order)
if h is not None:
print(f"\nTesting element of order {small_order}: h = {h}")
order_h = self.order_from_factorization(h)
print(f"Computed order: {order_h}")
print(f"Correct: {order_h == small_order}")
def benchmark_order_algorithms(self, test_elements=None):
if test_elements is None:
test_elements = [self.generator, self.generator**2, self.generator**5]
print("\nBenchmarking order computation algorithms...")
print("Element | Trial (ms) | Factor (ms) | Pollard (ms)")
print("-" * 50)
import time
for g in test_elements:
start = time.time()
order_trial = self.trial_division_order(g, max_iterations=10000)
time_trial = (time.time() - start) * 1000
start = time.time()
order_factor = self.order_from_factorization(g)
time_factor = (time.time() - start) * 1000
start = time.time()
order_rho = self.pollard_rho_order(g, max_iterations=10000)
time_rho = (time.time() - start) * 1000
print(">8.1f"
">8.1f"
">8.1f")
if order_trial != order_factor or (order_rho is not None and order_rho != order_factor):
print(" WARNING: Inconsistent results!")
if __name__ == "__main__":
p_small = 101
go_small = GroupOrderAlgorithms(p_small)
go_small.test_order_computation()
go_small.benchmark_order_algorithms()
p_large = 2**31 - 1 print(f"\nTesting with larger prime: {p_large}")
go_large = GroupOrderAlgorithms(p_large)
go_large.test_order_computation()