#!/usr/bin/env python3 from Cryptotools.Numbers.primeNumber import gcd, isPrimeNumber from Cryptotools.lcm import lcm from Cryptotools.Numbers.coprime import phi from Cryptotools.Utils.utils import gcd from sympy import factorint from functools import reduce def carmichael_lambda(n: int) -> int: """ This function is a carmichael lambda for identifying the smallest integer m and saisfy this condition: a ** m congrue 1 modulo n This function is relatively closed with the euler's totient (phi of n) Args: n (Integer): found the smallest integer of n Returns: REturn the smallest integer of n """ # First, factorizing n number # factorint return a list of prime factors of n # Base on that theorem: # https://en.wikipedia.org/wiki/Fundamental_theorem_of_arithmetic factorsN = factorint(n) """ The result of the factorint, we have the following: n = p ** e1, p ** e2, ..., p ** ek """ factors = list() for p, e in factorsN.items(): # Base on the theorem of arithmetic, p is always prime if isPrimeNumber(p): if p == 2 and e >= 3: factors.append(phi(pow(p, e)) // 2) elif p >= 2 and e > 0: factors.append(phi(pow(p, e))) elif p > 2: factors.append(phi(pow(p, e))) # Now, we can compute lcm result = reduce(lcm, factors) return result def carmichael_lambda2(n): """ Deprecated function """ # Get all coprimes with n coprimes = list() for a in range(1, n): if gcd(a, n) == 1: coprimes.append(a) # Need to find the smallest value """ Need to find the smallest value m. Must to satisfy this condition: a ** m congrus 1 mod n """ for m in range(1, n): print(f"{m} {a ** m % n}") print(coprimes) def carmi_numbers(n): """ This function get all GCD of the number if these number are prime or not Args: n (Integer): Iterate to n elements Returns: Return a list of prime numbers """ # https://kconrad.math.uconn.edu/blurbs/ugradnumthy/carmichaelkorselt.pdf primes = list() for i in range(2, n - 1): if gcd(n, i) == i: if isPrimeNumber(i): primes.append(i) return primes def is_carmichael(n, primes): """ This function check if the n number is a carmichael number. The arguments primes at least 3 prime numbers As it's said in the Carmichael theorem, a carmichael number has three factors and they are all primes: https://en.wikipedia.org/wiki/Carmichael_number With the Korselt's criterion, to check if the number is a carmichael number p - 1 / n - 1. Args: n (Integer): the carmichael number primes (list): list of prime numbers Returns: Boolean of the carmichael's number result """ r = True n = n - 1 if len(primes) < 3: return False # Korselt's criterion for p in primes: p = p - 1 if n % p != 0: r = False break return r def is_carmi_number(n) -> bool: """ This function check if the number n is a carmichael number (pseudoprime) Args: n (Integer): Iterate to n elements Returns: Return a Boolean if n is a carmichael number or not. True if yes """ j = 0 for i in range(n): if i ** n % n == i: j += 1 if j == n: return True return False def generate_carmi_numbers(nbr) -> list: """ This function generate carmichael numbers, they are called pseudoprimes For instance: a = 545, n = 561 gcd(a, n) = 1 pow(a, n - 1) % n = 1 Args: nbr (Integer): Find all pseudoprimes until nbr is achieves Returns: Return the list of pseudoprimes """ carmi = list() count = 0 n = 2 while count < nbr: # First, we need to find a, coprime with n for a in range(1, n): # We check if n is coprime with a # All integers must be coprime with n, a belong to n if gcd(a, n) == 1: # Check if is a carmichael number # Fermat's little theorem, a ** (n - 1) % n, must be congruent to 1 if pow(a, (n - 1)) % n == 1: #if (a ** (n - 1)) % n == 1: #print(f"{gcd(a, n)} {a} {n}") if n not in carmi: count += 1 carmi.append(n) else: print(f"{gcd(a, n)} {a} {n}") break n += 1 print(carmi) #for cop in range(2, n): # if gcd(cop, n) == 1: # coprimes.append(cop) return carmi