

"""simple docstring"""





from __future__ import annotations




def   _A  (  UpperCamelCase_					:	str,      UpperCamelCase_					:	list[str] | None = None,      UpperCamelCase_					:	dict[str, float] | None = None,      UpperCamelCase_					:	bool = False,      )     ->						tuple[int, float, str]:
   '''simple docstring'''


   __lowercase								=						cipher_alphabet or [chr(UpperCamelCase_) for i in range(97,      123)]

   # If the argument is None or the user provided an empty dictionary
   if not frequencies_dict:
      # Frequencies of letters in the english language (how much they show up)
      __lowercase								=						{
          "a": 0.08_497,
          "b": 0.01_492,
          "c": 0.02_202,
          "d": 0.04_253,
          "e": 0.11_162,
          "f": 0.02_228,
          "g": 0.02_015,
          "h": 0.06_094,
          "i": 0.07_546,
          "j": 0.00_153,
          "k": 0.01_292,
          "l": 0.04_025,
          "m": 0.02_406,
          "n": 0.06_749,
          "o": 0.07_507,
          "p": 0.01_929,
          "q": 0.00_095,
          "r": 0.07_587,
          "s": 0.06_327,
          "t": 0.09_356,
          "u": 0.02_758,
          "v": 0.00_978,
          "w": 0.02_560,
          "x": 0.00_150,
          "y": 0.01_994,
          "z": 0.00_077,
      }
   else:
      # Custom frequencies dictionary
      __lowercase								=						frequencies_dict

   if not case_sensitive:
      __lowercase								=						ciphertext.lower()

   # Chi squared statistic values
   __lowercase								=						{}

   # cycle through all of the shifts
   for shift in range(len(UpperCamelCase_)):
      __lowercase								=						""

      # decrypt the message with the shift
      for letter in ciphertext:
         try:
            # Try to index the letter in the alphabet
            __lowercase								=						(alphabet_letters.index(letter.lower()) - shift) % len(
                UpperCamelCase_)
            decrypted_with_shift += (
                alphabet_letters[new_key].upper()
                if case_sensitive and letter.isupper()
                else alphabet_letters[new_key]
            )
         except ValueError:
            # Append the character if it isn't in the alphabet
            decrypted_with_shift += letter

      __lowercase								=						0.0

      # Loop through each letter in the decoded message with the shift
      for letter in decrypted_with_shift:
         if case_sensitive:
            __lowercase								=						letter.lower()
            if letter in frequencies:
               # Get the amount of times the letter occurs in the message
               __lowercase								=						decrypted_with_shift.lower().count(UpperCamelCase_)

               # Get the excepcted amount of times the letter should appear based
               # on letter frequencies
               __lowercase								=						frequencies[letter] * occurrences

               # Complete the chi squared statistic formula
               __lowercase								=						((occurrences - expected) ** 2) / expected

               # Add the margin of error to the total chi squared statistic
               chi_squared_statistic += chi_letter_value
         else:
            if letter.lower() in frequencies:
               # Get the amount of times the letter occurs in the message
               __lowercase								=						decrypted_with_shift.count(UpperCamelCase_)

               # Get the excepcted amount of times the letter should appear based
               # on letter frequencies
               __lowercase								=						frequencies[letter] * occurrences

               # Complete the chi squared statistic formula
               __lowercase								=						((occurrences - expected) ** 2) / expected

               # Add the margin of error to the total chi squared statistic
               chi_squared_statistic += chi_letter_value

        # Add the data to the chi_squared_statistic_values dictionary
      __lowercase								=						(
          chi_squared_statistic,
          decrypted_with_shift,
      )

   # Get the most likely cipher by finding the cipher with the smallest chi squared
   # statistic
   def chi_squared_statistic_values_sorting_key(UpperCamelCase_					:	int) -> tuple[float, str]:
      return chi_squared_statistic_values[key]

   __lowercase								=						min(
       UpperCamelCase_,      key=UpperCamelCase_,      )

   # Get all the data from the most likely cipher (key, decoded message)
   (
       (
       __lowercase
   )		,(
       __lowercase
   )		,
   )								=						chi_squared_statistic_values[most_likely_cipher]

   # Return the data on the most likely shift
   return (
       most_likely_cipher,
       most_likely_cipher_chi_squared_value,
       decoded_most_likely_cipher,
   )







"""simple docstring"""





import os
import random
import sys

from . import cryptomath_module as cryptoMath  # noqa: N812
from . import rabin_miller as rabinMiller  # noqa: N812




def   _A  (  )     ->						None:
   '''simple docstring'''


   print("Making key files...")
   make_key_files("rsa",      1024)
   print("Key files generation successful.")




def   _A  (  UpperCamelCase_					:	int)     ->						tuple[tuple[int, int], tuple[int, int]]:
   '''simple docstring'''


   print("Generating prime p...")
   __lowercase								=						rabinMiller.generate_large_prime(UpperCamelCase_)
   print("Generating prime q...")
   __lowercase								=						rabinMiller.generate_large_prime(UpperCamelCase_)
   __lowercase								=						p * q

   print("Generating e that is relatively prime to (p - 1) * (q - 1)...")
   while True:
      __lowercase								=						random.randrange(2 ** (key_size - 1),      2 ** (key_size))
      if cryptoMath.gcd(UpperCamelCase_,      (p - 1) * (q - 1)) == 1:
         break

   print("Calculating d that is mod inverse of e...")
   __lowercase								=						cryptoMath.find_mod_inverse(UpperCamelCase_,      (p - 1) * (q - 1))

   __lowercase								=						(n, e)
   __lowercase								=						(n, d)
   return (public_key, private_key)




def   _A  (  UpperCamelCase_					:	str,      UpperCamelCase_					:	int)     ->						None:
   '''simple docstring'''


   if os.path.exists(F"""{name}_pubkey.txt""") or os.path.exists(F"""{name}_privkey.txt"""):
      print("\nWARNING:")
      print(
          F"""\"{name}_pubkey.txt\" or \"{name}_privkey.txt\" already exists. \n"""
          "Use a different name or delete these files and re-run this program.")
      sys.exit()

   __lowercase		,__lowercase								=						generate_key(UpperCamelCase_)
   print(F"""\nWriting public key to file {name}_pubkey.txt...""")
   with open(F"""{name}_pubkey.txt""",      "w") as out_file:
      out_file.write(F"""{key_size},{public_key[0]},{public_key[1]}""")

   print(F"""Writing private key to file {name}_privkey.txt...""")
   with open(F"""{name}_privkey.txt""",      "w") as out_file:
      out_file.write(F"""{key_size},{private_key[0]},{private_key[1]}""")


if __name__ == "__main__":
   main()




