"""Convert various I2P address formats to a 32-byte hash. Ported from net.i2p.util.ConvertToHash. """ from __future__ import annotations import base64 def convert_to_hash(input_str: str) -> bytes | None: """Convert a Base64 hash, .b32.i2p address, or full destination to a 32-byte hash. Returns None if the input is not a recognized format. """ if not input_str: return None # 43 or 44-char Base64 → raw 32-byte hash # I2P uses modified Base64: -~ instead of +/ # 32 bytes = 43 Base64 chars + 1 padding, or 44 chars if padding included if len(input_str) in (43, 44) and not input_str.endswith(".i2p"): try: std = input_str.replace("-", "+").replace("~", "/") # Pad to multiple of 4 pad = (4 - len(std) % 4) % 4 decoded = base64.b64decode(std + "=" * pad) if len(decoded) == 32: return decoded except Exception: pass return None # 52-char-prefix.b32.i2p → Base32 decode to 32 bytes if input_str.endswith(".b32.i2p"): b32_part = input_str[: -len(".b32.i2p")] if len(b32_part) == 52: try: decoded = base64.b32decode(b32_part.upper() + "====") if len(decoded) == 32: return decoded except Exception: pass return None return None