



"""simple docstring"""







import string

import numpy

def  __SCREAMING_SNAKE_CASE		(			lowerCamelCase_:							int     ,		lowerCamelCase_:							int ):
						"""simple docstring"""






						return b if a == 0 else greatest_common_divisor(b % a     ,		lowerCamelCase_ )

class       _a  :
			__magic_name__     					=     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)
			__magic_name__     					=     numpy.vectorize(lambda SCREAMING_SNAKE_CASE__: x % 36)

			__magic_name__     					=     numpy.vectorize(SCREAMING_SNAKE_CASE__)



			def __init__(			self							:				Any   ,	_lowercase							:				numpy.ndarray		)							->					None:
									snake_case   :			Tuple						    = self.modulus(_lowercase		)  # mod36 calc's on the encrypt key
									self.check_determinant()  # validate the determinant of the encryption key
									snake_case   :			Any						    = encrypt_key.shape[0]



			def 				__lowercase					(			self							:				List[Any]   ,	_lowercase							:				str		)							->					int:
									return self.key_string.index(_lowercase		)



			def 				__lowercase					(			self							:				List[str]   ,	_lowercase							:				int		)							->					str:
									return self.key_string[round(_lowercase		)]



			def 				__lowercase					(			self							:				Optional[int]		)							->					None:
									snake_case   :			Union[str, Any]						    = round(numpy.linalg.det(self.encrypt_key		)		)

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

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



			def 				__lowercase					(			self							:				Optional[int]   ,	_lowercase							:				str		)							->					str:
									snake_case   :			Optional[Any]						    = [char for char in text.upper() if char in self.key_string]

									snake_case   :			Dict						    = chars[-1]
									while len(_lowercase		) % self.break_key != 0:
															chars.append(_lowercase		)

									return "".join(_lowercase		)



			def 				__lowercase					(			self							:				Tuple   ,	_lowercase							:				str		)							->					str:
									snake_case   :			str						    = self.process_text(text.upper()		)
									snake_case   :			Union[str, Any]						    = ""

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

									return encrypted



			def 				__lowercase					(			self							:				Optional[Any]		)							->					numpy.ndarray:
									snake_case   :			Optional[Any]						    = round(numpy.linalg.det(self.encrypt_key		)		)

									if det < 0:
															snake_case   :			Any						    = det % len(self.key_string		)
									snake_case   :			List[str]						    = None
									for i in range(len(self.key_string		)		):
															if (det * i) % len(self.key_string		) == 1:
																					snake_case   :			Tuple						    = i
																					break

									snake_case   :			Tuple						    = (
									    det_inv
									    * numpy.linalg.det(self.encrypt_key		)
									    * numpy.linalg.inv(self.encrypt_key		)
									)

									return self.to_int(self.modulus(_lowercase		)		)



			def 				__lowercase					(			self							:				Union[str, Any]   ,	_lowercase							:				str		)							->					str:
									snake_case   :			Any						    = self.make_decrypt_key()
									snake_case   :			int						    = self.process_text(text.upper()		)
									snake_case   :			str						    = ""

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

									return decrypted



def  __SCREAMING_SNAKE_CASE		(			):
						"""simple docstring"""






						snake_case   :			Any						    = int(input("Enter the order of the encryption key: " ) )
						snake_case   :			Tuple						    = []

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

						snake_case   :			Optional[int]						    = HillCipher(numpy.array(lowerCamelCase_ ) )

						print("Would you like to encrypt or decrypt some text? (1 or 2)" )
						snake_case   :			List[str]						    = input("\n1. Encrypt\n2. Decrypt\n" )
						if option == "1":
												snake_case   :			int						    = input("What text would you like to encrypt?: " )
												print("Your encrypted text is:" )
												print(hc.encrypt(lowerCamelCase_ ) )
						elif option == "2":
												snake_case   :			Tuple						    = input("What text would you like to decrypt?: " )
												print("Your decrypted text is:" )
												print(hc.decrypt(lowerCamelCase_ ) )


if __name__ == "__main__":
			import doctest

			doctest.testmod()

			main()








"""simple docstring"""







def  __SCREAMING_SNAKE_CASE		(			lowerCamelCase_:							int     ,		lowerCamelCase_:							int ):
						"""simple docstring"""






						return int((input_a, input_a).count(0 ) != 0 )

def  __SCREAMING_SNAKE_CASE		(			):
						"""simple docstring"""






						assert nand_gate(0     ,		0 ) == 1
						assert nand_gate(0     ,		1 ) == 1
						assert nand_gate(1     ,		0 ) == 1
						assert nand_gate(1     ,		1 ) == 0


if __name__ == "__main__":
			print(nand_gate(0, 0))
			print(nand_gate(0, 1))
			print(nand_gate(1, 0))
			print(nand_gate(1, 1))



