nym-lp-data
Trait definitions and data structures for Lewes Protocol (LP) processing pipelines in the Nym mixnet.
This crate is a vocabulary crate — it defines the traits that clients and mix nodes implement to compose a packet-processing pipeline, plus a few generic data wrappers (TimedData, AddressedTimedData, PipelineData) that thread per-packet state through every stage. It contains no concrete cryptography, transport, or network code. A concrete implementation live in nym-mix-sim.
Crate layout
| Module | Purpose |
|---|---|
common |
Wire-layer traits (Framing, FramingUnwrap, Transport, TransportUnwrap) and their composed supertraits (WireWrappingPipeline, WireUnwrappingPipeline) shared by both clients and mixnodes, plus NoOpWireWrapper / NoOpWireUnwrapper marker traits for opting into a pass-through wire layer |
clients |
Client-side outbound/inbound pipeline traits: Chunking, Reliability, Obfuscation, RoutingSecurity, plus the supertraits ClientWrappingPipeline / ClientUnwrappingPipeline, a Pipeline composition struct, no-op marker traits, and a tick-driven ClientWrappingPipelineDriver |
mixnodes |
Mixnode processing trait NymNodeProcessingPipeline (unwrap → mix → re-wrap) and a Pipeline composition struct |
Core data types
TimedData<Ts, D> ── pairs a value of type D with a timestamp Ts
TimedPayload<Ts> ── alias for TimedData<Ts, Vec<u8>>
AddressedTimedData<Ts, D, NdId> ── TimedData plus a destination address
AddressedTimedPayload<Ts, NdId> ── alias for AddressedTimedData<Ts, Vec<u8>, NdId>
PipelineData<Ts, D, Opts, NdId> ── TimedData plus per-message Opts
(used inside the client wrapping pipeline)
PipelinePayload<Ts, Opts, NdId> ── alias for PipelineData<Ts, Vec<u8>, Opts, NdId>
Ts is the timestamp / tick-context type, NdId is the next-hop identifier type, and Opts is an InputOptions-implementing per-message marker that toggles which optional pipeline stages run for a given payload (reliability, obfuscation, routing security).
Client wrapping pipeline
The outbound client pipeline composes six stages, each represented by its own trait:
Vec<u8> ──▶ Chunking ──▶ Reliability ──▶ Obfuscation
│
▼
AddressedTimedData<Ts, Pkt, NdId> ◀── Transport ◀── Framing ◀── RoutingSecurity
ClientWrappingPipeline is the supertrait that ties them together and provides a default process() method which runs all six stages in order on every tick. Each stage is opt-in per message via the active InputOptions.
Pipeline tick semantics
process() is intended to be called on every tick (with or without an input payload):
Reliability::reliable_encodeis always called once withSome(input)(when present), then once more withNoneso that timer-driven retransmissions can fire even when no new payload arrived.Obfuscation::obfuscatefollows the same pattern — once with the real input and once withNoneso that cover-traffic loops can fire on idle ticks.ChunkingandRoutingSecurityonly run when a payload is actually present.
This convention is what allows pipelines to support Poisson cover traffic and SURB-ACK retransmission without the caller having to know whether anything is in flight.
Mixnode processing pipeline
The mixnode pipeline is simpler — three stages that consume a packet and emit zero or more re-wrapped output packets:
Pkt ──▶ WireUnwrappingPipeline ──▶ mix ──▶ WireWrappingPipeline ──▶ Vec<AddressedTimedData<Ts, Pkt, NdId>>
(TransportUnwrap + ▲ (Framing + Transport)
FramingUnwrap) │
└── implementor decrypts, routes,
schedules delays, etc.
Implementors fill in mix(); everything else is provided by the NymNodeProcessingPipeline supertrait's default process().
Helpers
- Client-stage no-op marker traits (
NoOpReliability,NoOpRoutingSecurity,NoOpObfuscationinclients/helpers.rs) — implement these to opt out of a pipeline stage with zero overhead. Useful for stub or testing pipelines. - Wire-layer no-op marker traits (
NoOpWireWrapper,NoOpWireUnwrapperincommon/helpers.rs) — collapse the entire wire layer (framing + transport, or their inverses) to a pass-through. Use these when your packet type is already self-contained on the wire (e.g. a Sphinx packet) and needs no extra framing or transport header.NoOpWireWrapperrequiresPkt: From<Vec<u8>>;NoOpWireUnwrapperrequiresPkt: Into<Vec<u8>>andMk: Default. Pipelinecomposition structs (inclients/types.rs) — generic structs that aggregate one component per pipeline stage and provide blanket impls of the relevant supertraits, so you can build a working pipeline by plugging in any combination of stage implementations.ClientWrappingPipelineDriver— wraps a dyn-compatible client pipeline behind a tick-driventick(timestamp) -> Vec<(Pkt, NdId)>interface, with an internal mpsc channel for application-supplied input payloads. Reads new input only when the internal buffer is empty so buffered packets do not stack additional latency on top.
Example users
nym-mix-sim is the reference consumer: it ships two complete pipeline implementations (a pass-through Simple* family and a full Sphinx + Poisson + SURB-ACK family) on top of the traits defined here. See its source for end-to-end examples of implementing each pipeline stage.
The integration test under tests/integration wires together a small synthetic pipeline (MockChunking, KcpReliability, SphinxSecurity, KekwObfuscation, LpFraming, LpTransport) against the nym-lp packet types — a useful starting point if you want to read a self-contained example of every trait being implemented.