std only.Expand description
Traffic shaping — anti-fingerprint size padding (WIRE v6, deliverable (c)).
The data-plane datagram size otherwise tracks the application payload size (even with the v6 length-prefix diet, the datagram length is observable). This module hides it by padding each packet up to a size bucket before it is sealed, so an on-path observer sees only a small set of sizes.
Padding lives inside the AEAD plaintext (encrypted + authenticated), so a
network attacker can neither see it, strip it, nor forge it — only the bucketed
datagram size is observable. A padded packet sets
PacketFlags::PADDED; its
plaintext gains a trailer ‹pad_n zero bytes› ‖ pad_n:u16be, which the receiver
strips after a successful decrypt.
The policy that picks the bucket is PADÉ (Nikitin et al., “PURBs”, 2019):
a length is rounded up so its low E−S bits are zero (E = ⌊log2 L⌋,
S = ⌊log2 E⌋+1), which caps the overhead at ≈ 1/E (≤ ~12% for small
packets, →0 for large) while collapsing the size distribution to O(log) values
per magnitude. Far cheaper than pad-to-MTU, far better than fixed buckets near
their edges.
Pure + no_std-friendly (no allocation in the size math; append/strip
operate on caller buffers). Default policy is PaddingPolicy::None — shaping
is fully opt-in (it costs bandwidth).
Enums§
- Padding
Policy - How a packet’s on-wire size is chosen before sealing.
Constants§
- MAX_
SHAPED_ WIRE - Upper bound on the padded on-wire packet size (the
PhantomPacketwire image: 15-byte header + ciphertext). Capped below the 1200-byte path MTU with margin for the largest transport envelope (the 8-byte UDPConnId, plus slack), so a padded datagram never fragments. A packet already larger than this is not padded (it is near-MTU already — low size entropy). - PAD_
LEN_ FIELD - Size of the in-plaintext padding length field (
pad_n: u16be). The minimum trailer a padded packet carries (withpad_n == 0zero bytes).
Functions§
- append_
padding - Append a padding trailer of
trailertotal bytes toplaintext:(trailer − PAD_LEN_FIELD)zero bytes, then the big-endianu16count of those zero bytes.trailermust be≥ PAD_LEN_FIELDand≤ u16::MAX + PAD_LEN_FIELD(callers gettrailerfrompadding_trailer_len, which respects both). Atrailer < PAD_LEN_FIELDis a no-op (defensive). - padding_
trailer_ len - The number of trailer bytes to append to the AEAD plaintext to bring the
resulting on-wire packet to a PADÉ bucket.
0when no padding applies (policyNone, or the packet is already too large to pad underMAX_SHAPED_WIRE). When non-zero it is≥ PAD_LEN_FIELD(the 2-byte length field plus zero fill). - padme
- PADÉ: round
lup so its lowE−Sbits are zero, whereE = ⌊log2 l⌋andS = ⌊log2 E⌋ + 1. Returnslunchanged forl ≤ 2(nothing to round). Monotone non-decreasing and idempotent; overhead(padme(l) − l)/l < 2^−S. - random_
jitter - Anti-fingerprint timing jitter (WIRE v6, deliverable (d)): a uniform random
delay in
[0, max_ms]milliseconds to add before a send, so the inter-packet timing no longer tracks the application’s write pattern. ReturnsDuration::ZEROwhenmax_ms == 0(jitter off). Opt-in; it trades up tomax_msof added latency per packet for timing-correlation resistance. - strip_
padding - Strip a padding trailer from a decrypted,
PADDED-flagged plaintext: read the trailingu16bepad length, then drop that many zero bytes plus the 2-byte field. Returns the inner plaintext slice. A trailer that claims more bytes than are present isWireError::Truncated(an authenticated peer cannot reach this with a malformed trailer — the AEAD already verified — but a buggy peer must not panic the receiver).