
import mpmath  # for roots of unity
import numpy as np
class 					lowercase__:



	"""simple docstring"""




	def __init__(			self    :     List[str]			,				SCREAMING_SNAKE_CASE_    :     Optional[Any]=None			,				SCREAMING_SNAKE_CASE_    :     Optional[Any]=None			)			->	Union[str, Any]:
					# Input as list
					lowercase_	    =   list(poly_a or [0]			)[:]
					lowercase_	    =   list(poly_b or [0]			)[:]

					# Remove leading zero coefficients
					while self.polyA[-1] == 0:
									self.polyA.pop()
					lowercase_	    =   len(self.polyA			)

					while self.polyB[-1] == 0:
									self.polyB.pop()
					lowercase_	    =   len(self.polyB			)

					# Add 0 to make lengths equal a power of 2
					lowercase_	    =   int(
					    2 ** np.ceil(np.loga(len(self.polyA			) + len(self.polyB			) - 1			)			)			)

					while len(self.polyA			) < self.c_max_length:
									self.polyA.append(0			)
					while len(self.polyB			) < self.c_max_length:
									self.polyB.append(0			)
					# A complex root used for the fourier transform
					lowercase_	    =   complex(mpmath.root(x=1			,				n=self.c_max_length			,				k=1			)			)

					# The product
					lowercase_	    =   self.__multiply()
	def 		_lowercase    (			self    :     Optional[Any]			,				SCREAMING_SNAKE_CASE_    :     List[Any]			)			->	Any:
					lowercase_	    =   [[x] for x in self.polyA] if which == '''A''' else [[x] for x in self.polyB]
					# Corner case
					if len(SCREAMING_SNAKE_CASE_			) <= 1:
									return dft[0]
					#
					lowercase_	    =   self.c_max_length // 2
					while next_ncol > 0:
									lowercase_	    =   [[] for i in range(SCREAMING_SNAKE_CASE_			)]
									lowercase_	    =   self.root**next_ncol

									# First half of next step
									lowercase_	    =   1
									for j in range(self.c_max_length // (next_ncol * 2)			):
													for i in range(SCREAMING_SNAKE_CASE_			):
																	new_dft[i].append(dft[i][j] + current_root * dft[i + next_ncol][j]			)
													current_root *= root
									# Second half of next step
									lowercase_	    =   1
									for j in range(self.c_max_length // (next_ncol * 2)			):
													for i in range(SCREAMING_SNAKE_CASE_			):
																	new_dft[i].append(dft[i][j] - current_root * dft[i + next_ncol][j]			)
													current_root *= root
									# Update
									lowercase_	    =   new_dft
									lowercase_	    =   next_ncol // 2
					return dft[0]
	def 		_lowercase    (			self    :     Dict			)			->	Tuple:
					lowercase_	    =   self.__dft('''A'''			)
					lowercase_	    =   self.__dft('''B'''			)
					lowercase_	    =   [[dft_a[i] * dft_b[i] for i in range(self.c_max_length			)]]
					del dft_a
					del dft_b

					# Corner Case
					if len(inverce_c[0]			) <= 1:
									return inverce_c[0]
					# Inverse DFT
					lowercase_	    =   2
					while next_ncol <= self.c_max_length:
									lowercase_	    =   [[] for i in range(SCREAMING_SNAKE_CASE_			)]
									lowercase_	    =   self.root ** (next_ncol // 2)
									lowercase_	    =   1
									# First half of next step
									for j in range(self.c_max_length // next_ncol			):
													for i in range(next_ncol // 2			):
																	# Even positions
																	new_inverse_c[i].append(
																	    (
																	        inverce_c[i][j]
																	        + inverce_c[i][j + self.c_max_length // next_ncol]
																	    )
																	    / 2			)
																	# Odd positions
																	new_inverse_c[i + next_ncol // 2].append(
																	    (
																	        inverce_c[i][j]
																	        - inverce_c[i][j + self.c_max_length // next_ncol]
																	    )
																	    / (2 * current_root)			)
													current_root *= root
									# Update
									lowercase_	    =   new_inverse_c
									next_ncol *= 2
					# Unpack
					lowercase_	    =   [round(x[0].real			,				8			) + round(x[0].imag			,				8			) * 1J for x in inverce_c]

					# Remove leading 0's
					while inverce_c[-1] == 0:
									inverce_c.pop()
					return inverce_c




	def __str__(			self    :     str			)			->	List[Any]:
					lowercase_	    =   '''A = ''' + ''' + '''.join(
					    f'''{coef}*x^{i}''' for coef, i in enumerate(self.polyA[: self.len_A]			)			)
					lowercase_	    =   '''B = ''' + ''' + '''.join(
					    f'''{coef}*x^{i}''' for coef, i in enumerate(self.polyB[: self.len_B]			)			)
					lowercase_	    =   '''A*B = ''' + ''' + '''.join(
					    f'''{coef}*x^{i}''' for coef, i in enumerate(self.product			)			)

					return f'''{a}\n{b}\n{c}'''


# Unit tests
if __name__ == "__main__":
						import doctest

						doctest.testmod()










'''simple docstring'''


from collections.abc import Generator
from math import sin
def 						snake_case_       (UpperCamelCase			:    bytes ):





							'''simple docstring'''


							if len(UpperCamelCase ) != 32:
														raise ValueError('''Input must be of length 32''' )

							_a      	=							B''''''
							for i in [3, 2, 1, 0]:
														little_endian += string_aa[8 * i : 8 * i + 8]
							return little_endian
def 						snake_case_       (UpperCamelCase			:    int ):





							'''simple docstring'''


							if i < 0:
														raise ValueError('''Input must be non-negative''' )

							_a      	=							format(UpperCamelCase					,		'''08x''' )[-8:]
							_a      	=							B''''''
							for i in [3, 2, 1, 0]:
														little_endian_hex += hex_rep[2 * i : 2 * i + 2].encode('''utf-8''' )
							return little_endian_hex
def 						snake_case_       (UpperCamelCase			:    bytes ):





							'''simple docstring'''


							_a      	=							B''''''
							for char in message:
														bit_string += format(UpperCamelCase					,		'''08b''' ).encode('''utf-8''' )
							_a      	=							format(len(UpperCamelCase )					,		'''064b''' ).encode('''utf-8''' )

							# Pad bit_string to a multiple of 512 chars
							bit_string += b"1"
							while len(UpperCamelCase ) % 512 != 448:
														bit_string += b"0"
							bit_string += to_little_endian(start_len[32:] ) + to_little_endian(start_len[:32] )

							return bit_string
def 						snake_case_       (UpperCamelCase			:    bytes ):





							'''simple docstring'''


							if len(UpperCamelCase ) % 512 != 0:
														raise ValueError('''Input must have length that\'s a multiple of 512''' )

							for pos in range(0					,		len(UpperCamelCase )					,		512 ):
														_a      	=							bit_string[pos : pos + 512]
														_a      	=							[]
														for i in range(0					,		512					,		32 ):
																					block_words.append(int(to_little_endian(block[i : i + 32] )					,		2 ) )
														yield block_words
def 						snake_case_       (UpperCamelCase			:    int ):





							'''simple docstring'''


							if i < 0:
														raise ValueError('''Input must be non-negative''' )

							_a      	=							format(UpperCamelCase					,		'''032b''' )
							_a      	=							''''''
							for c in i_str:
														new_str += "1" if c == "0" else "0"
							return int(UpperCamelCase					,		2 )
def 						snake_case_       (UpperCamelCase			:    int					,		UpperCamelCase			:    int ):





							'''simple docstring'''


							return (a + b) % 2**32
def 						snake_case_       (UpperCamelCase			:    int					,		UpperCamelCase			:    int ):





							'''simple docstring'''


							if i < 0:
														raise ValueError('''Input must be non-negative''' )
							if shift < 0:
														raise ValueError('''Shift must be non-negative''' )
							return ((i << shift) ^ (i >> (32 - shift))) % 2**32
def 						snake_case_       (UpperCamelCase			:    bytes ):





							'''simple docstring'''


							_a      	=							preprocess(UpperCamelCase )

							_a      	=							[int(2**32 * abs(sin(i + 1 ) ) ) for i in range(64 )]

							# Starting states
							_a      	=							0X67452301
							_a      	=							0Xefcdab89
							_a      	=							0X98badcfe
							_a      	=							0X10325476

							_a      	=							[
							    7,
							    12,
							    17,
							    22,
							    7,
							    12,
							    17,
							    22,
							    7,
							    12,
							    17,
							    22,
							    7,
							    12,
							    17,
							    22,
							    5,
							    9,
							    14,
							    20,
							    5,
							    9,
							    14,
							    20,
							    5,
							    9,
							    14,
							    20,
							    5,
							    9,
							    14,
							    20,
							    4,
							    11,
							    16,
							    23,
							    4,
							    11,
							    16,
							    23,
							    4,
							    11,
							    16,
							    23,
							    4,
							    11,
							    16,
							    23,
							    6,
							    10,
							    15,
							    21,
							    6,
							    10,
							    15,
							    21,
							    6,
							    10,
							    15,
							    21,
							    6,
							    10,
							    15,
							    21,
							]

							# Process bit string in chunks, each with 16 32-char words
							for block_words in get_block_words(UpperCamelCase ):
														_a      	=							aa
														_a      	=							ba
														_a      	=							ca
														_a      	=							da

														# Hash current chunk
														for i in range(64 ):
																					if i <= 15:
																												# f = (b & c) | (not_32(b) & d)     # Alternate definition for f
																												_a      	=							d ^ (b & (c ^ d))
																												_a      	=							i
																					elif i <= 31:
																												# f = (d & b) | (not_32(d) & c)     # Alternate definition for f
																												_a      	=							c ^ (d & (b ^ c))
																												_a      	=							(5 * i + 1) % 16
																					elif i <= 47:
																												_a      	=							b ^ c ^ d
																												_a      	=							(3 * i + 5) % 16
																					else:
																												_a      	=							c ^ (b | not_aa(UpperCamelCase ))
																												_a      	=							(7 * i) % 16
																					_a      	=							(f + a + added_consts[i] + block_words[g]) % 2**32
																					_a      	=							d
																					_a      	=							c
																					_a      	=							b
																					_a      	=							sum_aa(UpperCamelCase					,		left_rotate_aa(UpperCamelCase					,		shift_amounts[i] ) )

														# Add hashed chunk to running total
														_a      	=							sum_aa(UpperCamelCase					,		UpperCamelCase )
														_a      	=							sum_aa(UpperCamelCase					,		UpperCamelCase )
														_a      	=							sum_aa(UpperCamelCase					,		UpperCamelCase )
														_a      	=							sum_aa(UpperCamelCase					,		UpperCamelCase )

							_a      	=							reformat_hex(UpperCamelCase ) + reformat_hex(UpperCamelCase ) + reformat_hex(UpperCamelCase ) + reformat_hex(UpperCamelCase )
							return digest


if __name__ == "__main__":
				import doctest

				doctest.testmod()

