



import string

import numpy





def 		a__			(		_UpperCamelCase			: Tuple ,_UpperCamelCase			: Dict							):
   return b if a == 0 else greatest_common_divisor(b % a ,_UpperCamelCase							)



class  __lowerCAmelCase     :
 lowerCAmelCase__       					=  string.ascii_uppercase + string.digits
 # This cipher takes alphanumerics into account
 # i.e. a total of 36 characters

 # take x and return x % len(key_string)
 lowerCAmelCase__       					=  numpy.vectorize(lambda lowerCAmelCase__   : x % 3_6   )

 lowerCAmelCase__       					=  numpy.vectorize(lowerCAmelCase__   )




 def __init__(						self	,				__UpperCAmelCase				):



    '''simple docstring'''
    __lowerCamelCase													=    self.modulus(UpperCAmelCase__				)  # mod36 calc's on the encrypt key
    self.check_determinant()  # validate the determinant of the encryption key
    __lowerCamelCase													=    encrypt_key.shape[0]




 def        lowerCamelCase      (						self	,				__UpperCAmelCase				):



    '''simple docstring'''
    return self.key_string.index(UpperCAmelCase__				)




 def        lowerCamelCase      (						self	,				__UpperCAmelCase				):



    '''simple docstring'''
    return self.key_string[round(UpperCAmelCase__				)]




 def        lowerCamelCase      (						self				):



    '''simple docstring'''
    __lowerCamelCase													=    round(numpy.linalg.det(self.encrypt_key				)				)

    if det < 0:
       __lowerCamelCase													=    det % len(self.key_string				)

    __lowerCamelCase													=    len(self.key_string				)
    if greatest_common_divisor(UpperCAmelCase__	,				len(self.key_string				)				) != 1:
       __lowerCamelCase													=    (
           F"""determinant modular {req_l} of encryption key({det}) """
           F"""is not co prime w.r.t {req_l}.\nTry another key."""
       )
       raise ValueError(UpperCAmelCase__				)




 def        lowerCamelCase      (						self	,				__UpperCAmelCase				):



    '''simple docstring'''
    __lowerCamelCase													=    [char for char in text.upper() if char in self.key_string]

    __lowerCamelCase													=    chars[-1]
    while len(UpperCAmelCase__				) % self.break_key != 0:
       chars.append(UpperCAmelCase__				)

    return "".join(UpperCAmelCase__				)




 def        lowerCamelCase      (						self	,				__UpperCAmelCase				):



    '''simple docstring'''
    __lowerCamelCase													=    self.process_text(text.upper()				)
    __lowerCamelCase													=    ''''''

    for i in range(0	,				len(UpperCAmelCase__				) - self.break_key + 1	,				self.break_key				):
       __lowerCamelCase													=    text[i : i + self.break_key]
       __lowerCamelCase													=    [self.replace_letters(UpperCAmelCase__				) for char in batch]
       __lowerCamelCase													=    numpy.array([vec]				).T
       __lowerCamelCase													=    self.modulus(self.encrypt_key.dot(UpperCAmelCase__				)				).T.tolist()[
           0
       ]
       __lowerCamelCase													=    ''''''.join(
           self.replace_digits(UpperCAmelCase__				) for num in batch_encrypted				)
       encrypted += encrypted_batch

    return encrypted




 def        lowerCamelCase      (						self				):



    '''simple docstring'''
    __lowerCamelCase													=    round(numpy.linalg.det(self.encrypt_key				)				)

    if det < 0:
       __lowerCamelCase													=    det % len(self.key_string				)
    __lowerCamelCase													=    None
    for i in range(len(self.key_string				)				):
       if (det * i) % len(self.key_string				) == 1:
          __lowerCamelCase													=    i
          break

    __lowerCamelCase													=    (
        det_inv
        * numpy.linalg.det(self.encrypt_key				)
        * numpy.linalg.inv(self.encrypt_key				)
    )

    return self.to_int(self.modulus(UpperCAmelCase__				)				)




 def        lowerCamelCase      (						self	,				__UpperCAmelCase				):



    '''simple docstring'''
    __lowerCamelCase													=    self.make_decrypt_key()
    __lowerCamelCase													=    self.process_text(text.upper()				)
    __lowerCamelCase													=    ''''''

    for i in range(0	,				len(UpperCAmelCase__				) - self.break_key + 1	,				self.break_key				):
       __lowerCamelCase													=    text[i : i + self.break_key]
       __lowerCamelCase													=    [self.replace_letters(UpperCAmelCase__				) for char in batch]
       __lowerCamelCase													=    numpy.array([vec]				).T
       __lowerCamelCase													=    self.modulus(decrypt_key.dot(UpperCAmelCase__				)				).T.tolist()[0]
       __lowerCamelCase													=    ''''''.join(
           self.replace_digits(UpperCAmelCase__				) for num in batch_decrypted				)
       decrypted += decrypted_batch

    return decrypted





def 		a__			(		):
   __lowerCamelCase													=    int(input('''Enter the order of the encryption key: '''							)							)
   __lowerCamelCase													=    []

   print('''Enter each row of the encryption key with space separated integers'''							)
   for _ in range(_UpperCamelCase							):
      __lowerCamelCase													=    [int(_UpperCamelCase							) for x in input().split()]
      hill_matrix.append(_UpperCamelCase							)

   __lowerCamelCase													=    HillCipher(numpy.array(_UpperCamelCase							)							)

   print('''Would you like to encrypt or decrypt some text? (1 or 2)'''							)
   __lowerCamelCase													=    input('''\n1. Encrypt\n2. Decrypt\n'''							)
   if option == "1":
      __lowerCamelCase													=    input('''What text would you like to encrypt?: '''							)
      print('''Your encrypted text is:'''							)
      print(hc.encrypt(_UpperCamelCase							)							)
   elif option == "2":
      __lowerCamelCase													=    input('''What text would you like to decrypt?: '''							)
      print('''Your decrypted text is:'''							)
      print(hc.decrypt(_UpperCamelCase							)							)


if __name__ == "__main__":
  import doctest

  doctest.testmod()

  main()









def 		a__			(		_UpperCamelCase			: str ,_UpperCamelCase			: str = " "							):
   __lowerCamelCase													=    []

   __lowerCamelCase													=    0
   for index, char in enumerate(_UpperCamelCase							):
      if char == separator:
         split_words.append(string[last_index:index]							)
         __lowerCamelCase													=    index + 1
      elif index + 1 == len(_UpperCamelCase							):
         split_words.append(string[last_index : index + 1]							)
   return split_words


if __name__ == "__main__":
  from doctest import testmod

  testmod()






