


'''simple docstring'''

import string

import numpy






def 					_A			(			snake_case__    :			int						,						snake_case__    :			int				):
	return b if a == 0 else greatest_common_divisor(b % a						,						UpperCamelCase__				)

class 		snake_case				:

				"""simple docstring"""




				_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(_a						)





				def __init__(	self       ,    lowerCamelCase )    ->      Optional[int]:







					"""simple docstring"""






					snake_case__			:			List[Any]             =		self.modulus(A_ )  # mod36 calc's on the encrypt key
					self.check_determinant()  # validate the determinant of the encryption key
					snake_case__			:			Union[str, Any]             =		encrypt_key.shape[0]





				def    lowercase__							(	self       ,    lowerCamelCase )    ->      Dict:







					"""simple docstring"""






					return self.key_string.index(A_ )





				def    lowercase__							(	self       ,    lowerCamelCase )    ->      str:







					"""simple docstring"""






					return self.key_string[round(A_ )]





				def    lowercase__							(	self )    ->      int:







					"""simple docstring"""






					snake_case__			:			Tuple             =		round(numpy.linalg.det(self.encrypt_key ) )

					if det < 0:
						snake_case__			:			List[str]             =		det % len(self.key_string )

					snake_case__			:			Union[str, Any]             =		len(self.key_string )
					if greatest_common_divisor(A_       ,    len(self.key_string ) ) != 1:
						snake_case__			:			Optional[Any]             =		(
						    f'''determinant modular {req_l} of encryption key({det}) '''
						    f'''is not co prime w.r.t {req_l}.\nTry another key.'''
						)
						raise ValueError(A_ )





				def    lowercase__							(	self       ,    lowerCamelCase )    ->      Dict:







					"""simple docstring"""






					snake_case__			:			Optional[int]             =		[char for char in text.upper() if char in self.key_string]

					snake_case__			:			List[Any]             =		chars[-1]
					while len(A_ ) % self.break_key != 0:
						chars.append(A_ )

					return "".join(A_ )





				def    lowercase__							(	self       ,    lowerCamelCase )    ->      str:







					"""simple docstring"""






					snake_case__			:			Union[str, Any]             =		self.process_text(text.upper() )
					snake_case__			:			List[Any]             =		''''''

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

					return encrypted





				def    lowercase__							(	self )    ->      Optional[int]:







					"""simple docstring"""






					snake_case__			:			str             =		round(numpy.linalg.det(self.encrypt_key ) )

					if det < 0:
						snake_case__			:			Union[str, Any]             =		det % len(self.key_string )
					snake_case__			:			int             =		None
					for i in range(len(self.key_string ) ):
						if (det * i) % len(self.key_string ) == 1:
							snake_case__			:			Optional[int]             =		i
							break

					snake_case__			:			Optional[Any]             =		(
					    det_inv
					    * numpy.linalg.det(self.encrypt_key )
					    * numpy.linalg.inv(self.encrypt_key )
					)

					return self.to_int(self.modulus(A_ ) )





				def    lowercase__							(	self       ,    lowerCamelCase )    ->      Any:







					"""simple docstring"""






					snake_case__			:			Optional[int]             =		self.make_decrypt_key()
					snake_case__			:			Tuple             =		self.process_text(text.upper() )
					snake_case__			:			List[str]             =		''''''

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

					return decrypted






def 					_A			(			):
	snake_case__			:			Dict             =		int(input('''Enter the order of the encryption key: '''				)				)
	snake_case__			:			Union[str, Any]             =		[]

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

	snake_case__			:			Any             =		HillCipher(numpy.array(UpperCamelCase__				)				)

	print('''Would you like to encrypt or decrypt some text? (1 or 2)'''				)
	snake_case__			:			List[Any]             =		input('''\n1. Encrypt\n2. Decrypt\n'''				)
	if option == "1":
		snake_case__			:			str             =		input('''What text would you like to encrypt?: '''				)
		print('''Your encrypted text is:'''				)
		print(hc.encrypt(UpperCamelCase__				)				)
	elif option == "2":
		snake_case__			:			Tuple             =		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()









"""simple docstring"""

def lowerCAmelCase_   (					UpperCamelCase__						:			int			):






 """simple docstring"""







 assert (
     isinstance(UpperCamelCase__					, UpperCamelCase__			) and number_of_steps > 0
 ), f'''number_of_steps needs to be positive integer, your input {number_of_steps}'''
 if number_of_steps == 1:
  return 1
 __lowercase				,		__lowercase						=						1, 1
 for _ in range(number_of_steps - 1			):
  __lowercase				,		__lowercase						=						current + previous, current
 return current


if __name__ == "__main__":
       import doctest

       doctest.testmod()
