This post documents a work-in-progress analysis of integrating Rate Limiting Nullifier (RLN) with libp2p-mix for DoS and sybil protection. The full specification is documented here.
TL;DR: The RLN integration introduces two potential security gaps: i) an observable epoch field per hop, creating a periodic deanonymization window, and ii) a high blanket rate limit for outgoing packets that malicious nodes can exploit. Both gaps are medium severity.
1. Epoch Boundary Attack
Background
In Sphinx, all packets are fixed-size encrypted blobs with no observable per-packet metadata. A passive adversary watching a mix node sees indistinguishable ciphertexts arriving and departing. With random per-hop delays, the adversary is reduced to random guessing when attempting to map incoming packets to outgoing ones. For a batch of k incoming packets, the probability of correctly mapping one of them is 1/k, which is the intended security baseline. Mix delays exist precisely to hold the adversary at this level.
The RLN integration breaks this baseline for a specific, recurring class of packets by introducing an observable epoch field into every forwarded packet.
The Attack (Severity: Medium)
Each mix node generates a fresh RateLimitProof for each outgoing packet. The epoch value in that proof reflects the epoch at which the node generates the proof. Since the RateLimitProof is attached outside the Sphinx encrypted layer, it is observable to a passive adversary on the inter-node link.
Consider a mix node that receives k packets near the end of epoch N, with a small expected per-hop delay (e.g., one second). k-1 packets are processed before the epoch boundary; one is processed after. A passive adversary observing the outgoing stream sees a packet with epoch field N+1. Given small delays and no new incoming packet at epoch N+1 yet, this packet was almost certainly the last one received in epoch N — the one that arrived closest to the boundary.
This allows the adversary to map the packet with epoch field N+1 to the last-received incoming packet in the previous epoch with high confidence, reducing its anonymity from 1/k to ~1. The attack is most effective when the expected delay is small relative to the epoch duration, which is the common low-latency case. It recurs periodically at every epoch boundary.
Comparison with Sphinx
This attack does not exist in Sphinx. Without per-packet observable metadata, the adversary has no way to distinguish one outgoing packet from another. The epoch field is precisely what enables this attack.
Cover traffic mitigates this by increasing the overall traffic density, diluting the impact of such a per-packet signalling field. However, this makes cover traffic a harder requirement for anonymity than in standard mixnet design — a stronger assumption the specification MUST acknowledge.
Mitigation
The RateLimitProof can be encrypted for the next hop, using a component analogous to α in the Sphinx packet. Each forwarding node encrypts the proof using an ephemeral key derived from the next hop’s public key. The next hop then decrypts and verifies the proof locally. A passive adversary now sees only an encrypted blob and is reduced to random guessing even at epoch boundaries. However, this approach does not integrate cleanly as it requires extending the wire format and the per-hop processing pipeline. Alternative solutions need to be explored.
2. Rate Limit Amplification Gap
Background
A mix node is not exclusively an intermediary — it can also originate packets, acting as a sender. By design, forwarded and originated packets are indistinguishable. This is fundamental to sender anonymity.
The specification defines a rate limit R as the maximum number of outgoing packets per mix node in an epoch. RLN enforces this by detecting double-signalling: if there are more than R outgoing packets from a mix node in an epoch, its nullifier reuse is detectable and its secret key can be reconstructed for slashing. Both originated and forwarded packets count against this single rate limit R as they are indistinguishable.
The Attack (Severity: Medium)
Consider an honest mix node X. It can be chosen as an intermediary in many concurrent paths. Its total number of outgoing packets per epoch, P, scales with network traffic and is not bounded by R. Given that X generates a fresh RLN proof for each outgoing forwarded packet, forwarding counts against X’s own rate limit — not the sender’s. Therefore, to avoid being slashed, X requires a rate limit of at least P. But given that limit, X can even originate up to P packets per epoch.
Ideally, we want to enforce a forwarding limit of P and a sending limit of R packets per epoch. However, this is not possible since forwarded and originated packets are indistinguishable by design.
A malicious node, having obtained membership, can send up to P packets per epoch and remain entirely undetected. That is, the high rate limit set for intermediary operation effectively becomes a free allowance for malicious mix nodes — they can send more spam with no consequence.
Zero-knowledge proof generation can be a deterrent for malicious nodes. However, the cost is fixed per proof and does not escalate with the damage caused.
Even the membership stake is a fixed, one-time cost — a barrier to entry, not a rate-proportional deterrent.
Discussion
The following discussion is based on comments from @haelius and @prem.
One proposed design approach is to set R to be a generous limit — much larger than expected per-node traffic — so that forwarding load plus originated messages remain well below R for honest nodes, with cover traffic filling the remainder. Under this model, intermediaries that receive more than R messages simply drop the excess rather than requiring a higher registered rate limit.
This partially reframes the attack: the concern now becomes a targeted degradation attack — an adversary with N memberships floods a specific intermediary, filling its R forwarding slots with spam and starving legitimate traffic. The mitigation proposed is that senders route around degraded nodes with enough redundancy. However, this relies on detection mechanisms not currently defined in the spec, and does not hold if multiple nodes are targeted simultaneously.
Note that this assumes the attacker could register N memberships, which is costly.
Open Questions
- If mix nodes are required to send at a constant rate up to
Rthen each node generatesRRLN proofs per epoch. This has cost and performance implications. How shouldRbe chosen to ensure honest nodes are not flagged while keeping overall proof generation overhead minimal? - Is the degradation attack sufficiently mitigated by redundant path selection, and what detection mechanisms are needed?
- How membership is obtained remains an open question — the entire approach assumes some degree of sybil resistance, which is lost if memberships are easily obtainable. Token-based approaches (as used in Blend/Nym) may be needed long-term but introduce deeper on-chain dependencies.