"""Configuration objects for garlic message construction. Ported from net.i2p.router.crypto.GarlicConfig and PayloadGarlicConfig. These are builder-side data structures used before encryption — not wire format. """ from __future__ import annotations from dataclasses import dataclass, field NULL_CERT = b"\x00\x00\x00" @dataclass class CloveConfig: """Configuration for a single garlic clove. delivery_type values: 0=LOCAL, 1=DESTINATION, 2=ROUTER, 3=TUNNEL """ delivery_type: int message_data: bytes clove_id: int expiration: int dest_hash: bytes | None = None router_hash: bytes | None = None tunnel_id: int | None = None certificate: bytes = field(default_factory=lambda: NULL_CERT) request_ack: bool = False @classmethod def for_local( cls, message_data: bytes, clove_id: int, expiration: int, **kwargs, ) -> CloveConfig: """Create a LOCAL delivery clove.""" return cls( delivery_type=0, message_data=message_data, clove_id=clove_id, expiration=expiration, **kwargs, ) @classmethod def for_destination( cls, dest_hash: bytes, message_data: bytes, clove_id: int, expiration: int, **kwargs, ) -> CloveConfig: """Create a DESTINATION delivery clove.""" return cls( delivery_type=1, dest_hash=dest_hash, message_data=message_data, clove_id=clove_id, expiration=expiration, **kwargs, ) @classmethod def for_tunnel( cls, router_hash: bytes, tunnel_id: int, message_data: bytes, clove_id: int, expiration: int, **kwargs, ) -> CloveConfig: """Create a TUNNEL delivery clove.""" return cls( delivery_type=3, router_hash=router_hash, tunnel_id=tunnel_id, message_data=message_data, clove_id=clove_id, expiration=expiration, **kwargs, ) @dataclass class GarlicConfig: """Top-level garlic message configuration. Holds the recipient key and a list of cloves to encrypt together. """ recipient_public_key: bytes message_id: int expiration: int cloves: list[CloveConfig] = field(default_factory=list) def add_clove(self, clove: CloveConfig) -> None: self.cloves.append(clove) def clove_count(self) -> int: return len(self.cloves)