






import os
import random
import sys

from . import cryptomath_module as cryptomath
from . import rabin_miller

__UpperCAmelCase     							=						3




def 					lowercase__				(					__snake_case   :							int  ):


					'''simple docstring'''


					print('Generating primitive root of p'  )
					while True:
										UpperCAmelCase_   :				List[str]						=						random.randrange(3					,	__snake_case  )
										if pow(__snake_case					,	2					,	__snake_case  ) == 1:
															continue
										if pow(__snake_case					,	__snake_case					,	__snake_case  ) == 1:
															continue
										return g




def 					lowercase__				(					__snake_case   :							int  ):


					'''simple docstring'''


					print('Generating prime p...'  )
					UpperCAmelCase_   :				Tuple						=						rabin_miller.generate_large_prime(__snake_case  )  # select large prime number.
					UpperCAmelCase_   :				Tuple						=						primitive_root(__snake_case  )  # one primitive root on modulo p.
					UpperCAmelCase_   :				Any						=						random.randrange(3					,	__snake_case  )  # private_key -> have to be greater than 2 for safety.
					UpperCAmelCase_   :				str						=						cryptomath.find_mod_inverse(pow(__snake_case					,	__snake_case					,	__snake_case  )					,	__snake_case  )

					UpperCAmelCase_   :				Any						=						(key_size, e_a, e_a, p)
					UpperCAmelCase_   :				int						=						(key_size, d)

					return public_key, private_key




def 					lowercase__				(					__snake_case   :							str					,	__snake_case   :							int  ):


					'''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()

					UpperCAmelCase_	,  UpperCAmelCase_   :				Tuple						=						generate_key(__snake_case  )
					print(F"\nWriting public key to file {name}_pubkey.txt..."  )
					with open(F"{name}_pubkey.txt"					,	'w'  ) as fo:
										fo.write(F"{public_key[0]},{public_key[1]},{public_key[2]},{public_key[3]}"  )

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




def 					lowercase__				(					):


					'''simple docstring'''


					print('Making key files...'  )
					make_key_files('elgamal'					,	2_048  )
					print('Key files generation successful'  )


if __name__ == "__main__":
		main()














def 					lowercase__				(					__snake_case   :							str					,	__snake_case   :							int					,	__snake_case   :							List[str]  ):


					'''simple docstring'''


					if n == 0:
										return 1

					elif n % 2 == 1:
										return (binary_exponentiation(__snake_case					,	n - 1					,	__snake_case  ) * a) % mod

					else:
										UpperCAmelCase_   :				Optional[int]						=						binary_exponentiation(__snake_case					,	n / 2					,	__snake_case  )
										return (b * b) % mod


# a prime number
__UpperCAmelCase     							=						701

__UpperCAmelCase     							=						1000000000
__UpperCAmelCase     							=						10

# using binary exponentiation function, O(log(p)):
print((a / b) % p == (a * binary_exponentiation(b, p - 2, p)) % p)






print((a / b) % p == (a * b ** (p - 2)) % p)






