"""RoutingKeyGenerator — date-based routing key derivation for Kademlia. Ported from net.i2p.data.RoutingKeyGenerator. Routing keys rotate daily at midnight UTC. The routing key for a given database key is SHA-256(key + YYYY-MM-DD_UTF8). """ from __future__ import annotations import hashlib import time from datetime import datetime, timezone class RoutingKeyGenerator: """Generate date-based routing keys for NetDB lookups.""" def __init__(self) -> None: self._mod_data: bytes = b"" self._last_changed: float = 0.0 self.generate_date_based_mod_data() def get_routing_key(self, orig_key: bytes) -> bytes: """Compute the routing key: SHA-256(orig_key + mod_data).""" return hashlib.sha256(orig_key + self._mod_data).digest() def generate_date_based_mod_data(self) -> bool: """Update mod_data if the date has changed. Returns True if mod_data was updated. """ now = datetime.now(timezone.utc) new_mod = now.strftime("%Y-%m-%d").encode("ascii") if new_mod != self._mod_data: self._mod_data = new_mod self._last_changed = time.monotonic() return True return False def get_time_till_midnight_utc(self) -> float: """Seconds until the next UTC midnight.""" now = datetime.now(timezone.utc) tomorrow = now.replace( hour=0, minute=0, second=0, microsecond=0 ) # Move to next day from datetime import timedelta tomorrow += timedelta(days=1) return (tomorrow - now).total_seconds() @property def mod_data(self) -> bytes: return self._mod_data @property def last_changed(self) -> float: return self._last_changed