Spam Without a Moderator: How Waku's RLN Relay Rate-Limits a Permissionless Network
Waku's RLN Relay uses zero-knowledge rate-limiting nullifiers to stop spam in a permissionless pub/sub network — exceeding your message rate exposes your own secret key. Here's how it works and what it costs.
07 Jul 2026, 12:16 UTC

Open a pub/sub network to anyone and you get spam. Close it behind a central server that approves senders and you've rebuilt the thing you were trying to replace. Waku — the libp2p-based messaging stack that grew out of Ethereum's Whisper — faces this tension head-on, and its answer is RLN Relay: a way to enforce "one identity, N messages per epoch" using zero-knowledge proofs instead of a moderator.
This post explains how that mechanism actually works, walks through a concrete rate-limiting scenario, and covers the trade-offs you should weigh before building on it. Because Waku's RLN details (contract formats, epoch parameters, proof systems) have changed across releases, treat every specific number here as illustrative and confirm against the current Waku RFCs before shipping.
The problem RLN Relay solves
Waku's core transport is gossipsub: nodes relay messages on content topics, and any peer can publish. That's exactly what you want for censorship resistance, and exactly what a spammer wants too. Traditional fixes don't fit:
- Proof of work per message punishes phones and browsers as much as spammers.
- Central allowlists reintroduce a gatekeeper who can censor.
- Peer scoring alone slows abuse but doesn't create a real cost for misbehavior.
RLN (Rate-Limiting Nullifier) takes a different angle: make membership cheap and pseudonymous, but make exceeding a message rate self-destructive.
How the mechanism works
The flow, at a high level:
- Register. You generate a secret and insert a commitment (a hash of that secret) into a shared membership set — historically a Merkle tree whose root is tracked on-chain or distributed among peers. Registration may carry a stake or fee, depending on deployment.
- Prove per message. For each message, you attach a zero-knowledge proof showing two things: your commitment is in the membership tree, and you've computed a deterministic nullifier for the current epoch (a fixed time window, e.g. "epoch = 10 seconds"). The nullifier is derived from your secret and the epoch, so it's the same for you within one epoch but reveals nothing about who you are.
- Peers verify. Relaying nodes check the proof against the current Merkle root and epoch. Invalid proof → message dropped. This is cheap relative to generating the proof.
- Overuse exposes you. Here's the clever part: the proof includes shares of a linear equation (a Shamir-style construction). One message per epoch reveals nothing. Two messages in the same epoch give any observer two points on the line — enough to reconstruct your secret key. Once your secret is public, anyone can remove you from the membership set and claim or burn your stake.
So the protocol doesn't need to catch spammers in the act; the cryptography makes spamming equivalent to publishing your own credentials.
A worked example: picking a rate for a chat app
Say you're building a group chat on Waku and choose a limit of 1 message per 10-second epoch per member (a common reference configuration in Waku testnets — verify the current default).
A human typing sends maybe one message every few seconds, but bursts happen: someone pastes three lines at once. With a strict 1-per-epoch limit, two of those three messages would either be dropped by the client or, worse, published and expose the user's secret. Practical mitigations:
- Client-side queuing: the SDK buffers messages and releases one per epoch. Simple, but adds latency to bursts.
- Batching: pack several chat lines into one Waku message. This is usually the right answer — the rate limit counts Waku messages, not application messages.
- Multiple memberships: register N commitments for power users, giving them N messages per epoch. This works but weakens the spam cost model if memberships are cheap.
To sanity-check behavior on a test network, run a local node (nwaku or js-waku) with RLN Relay enabled, register a test membership, and publish two messages within one epoch. Expected result: peers reject the second proof or flag the double-signaling, and your secret becomes recoverable from the two proofs. Do this only on a test deployment — on a network with real stake, you'd lose it.
Trade-offs and limitations
It's a rate limiter, not moderation. RLN stops flooding. It does nothing about one carefully crafted abusive message per epoch. If your application needs content policy, you need a separate layer (client-side filtering, community blocklists, encrypted allowlists).
Proof cost lands on the sender. Generating a zk proof takes real CPU time — noticeable on mobile and in browsers. Waku's tiered architecture helps here: light clients using the filter and light-push protocols can delegate heavy relay work to service nodes, but proof generation for RLN still happens where the identity lives. Benchmark on your target hardware before committing.
Membership management is operational work. Someone must run the registration contract or distributed tree, handle slashing when secrets leak, and keep Merkle roots synchronized across peers. Root lag — a peer verifying against a stale root — is a real failure mode that can split the network's view of who's a member.
Epoch parameters are a policy decision. Shorter epochs with low limits favor interactive chat; longer epochs with higher limits favor bursty batch publishers. There is no universally correct setting, and changing it later is a network-wide coordination event.
What to do next
If RLN Relay fits your threat model — permissionless publishing, spam resistance, no central gatekeeper — start with a local two-node test network, register a throwaway membership, and deliberately exceed the rate limit to watch the enforcement path. Then read the current RLN Relay RFC for the exact epoch length, proof system, and contract ABI in the release you're targeting; those details have moved between versions and anything you read in a blog post (including this one) will drift. The design idea, though, is stable and worth stealing even outside Waku: make the cost of abuse cryptographic and automatic, not social and manual.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.