# modes/hash_mode.py import math class HashMode: """ Учебная хэш-функция. Варианты: 1 = sin-based 2 = cos-based 3 = xor-based """ def run(self, variant: str, message: str, salt: str = "", bytes: int = 16) -> str: if not (2 <= bytes <= 16): raise ValueError("Параметр bytes должен быть в диапазоне [2, 16]") data = (message + salt).encode("utf-8") if variant == "1": out = self._sin_hash(data) elif variant == "2": out = self._cos_hash(data) elif variant == "3": out = self._xor_hash(data) else: raise ValueError(f"Неизвестный вариант: {variant}") # Обрезаем до нужного числа байт truncated = self._truncate_bytes(out, bytes) return ''.join(f"{x:02x}" for x in truncated) # --- служебные ------------------------------------------------------ def _truncate_bytes(self, out: bytearray, bytes: int) -> bytearray: if bytes >= len(out): return out truncated = out[:bytes] # примешиваем все отброшенные байты в оставшиеся for i, b in enumerate(out[bytes:], start=1): truncated[i % len(truncated)] ^= b return truncated # --- реализации ------------------------------------------------------ def _sin_hash(self, data: bytes) -> bytearray: out = [0x55 ^ i for i in range(16)] if not data: return out angle = (2 * math.pi) / (len(out) * len(data)) for i, b in enumerate(data, 1): for j in range(len(out)): val = int((math.sin(b + (i + j) * angle) + 1) * 127) out[j] ^= val & 0xFF return out def _cos_hash(self, data: bytes) -> bytearray: out = [0x77 ^ i for i in range(16)] if not data: return out angle = (2 * math.pi) / (len(out) * len(data)) for i, b in enumerate(data, 1): for j in range(len(out)): val = int((math.cos(b + (i + j) * angle) + 1) * 127) out[j] ^= val & 0xFF return out def _mix_bits(self, mix: int) -> bytearray: # количество байт у числа = (битовая длина + 7) // 8 count = (mix.bit_length() + 7) // 8 for i in range(1, count): mix ^= (mix >> (8 * i)) return mix def _xor_hash(self, data: bytes) -> bytearray: out = [0xAA ^ i for i in range(16)] if not data: return out phi = (1 + 5 ** 0.5) / 2 # золотое сечение for i, b in enumerate(data, 1): for j in range(16): mix = (b * (i + j + 1)) ^ int(phi * 1e6) mix = self._mix_bits(mix) out[j] ^= mix & 0xFF # только младший байт return out