The security objective is to control the number of PubSub messages that each peer can publish per epoch where epoch is a system design parameter, regardless of the published topic.
For the registration, a peer creates a transaction that sends x (TODO to be specified) ETH to the contract.
The peer who has the "private key" `sk` associated with that deposit would be able to withdraw x ETH by providing valid proof.
Note that `sk` is initially only known by the owning peer however it may get exposed to other peers in case the owner attempts spamming the system i.e., sending more than one message per epoch.
<!-- Once registered, the peer obtains the root of the tree (after the registration of the current peer) i.e., `root` as well as the authenticity path `authPath`. A peer can prove her membership using the `authPath`. -->
In order to publish at a given `epoch`, the publishing peer proceeds based on the regular relay protocol.
However, in order to protect against spamming, each PubSub message must carry a `proof`.
At a high level, the `proof` is a zero-knowledge proof signifying that the publishing peer is a registered member, and she has not exceeded the messaging rate at the given `epoch`.
<!-- TODO: to clarify what a zero-knowledge proof means -->
The `proof` is embedded inside the `data` field of the PubSub message, which, in the [11/WAKU2-RELAY](/spec/11) protocol, corresponds to the [14/WAKU2-MESSAGE](/spec/14).
The proof generation relies on the knowledge of two pieces of private information i.e., `sk` and `authPath`.
`authPath` is the information by which one can prove its membership in the group. <!-- TODO explain what is atuh path -->
To construct `authPath`, peers need to locally store a Merkle tree out of the group members public keys.
Peers need to keep the tree updated with the recent state of the group.
Further inputs to the proof generation which are public are tree's `root`, `epoch` and `payload||contentTopic` where `payload` and `contentTopic` come from the `WakuMessage`.
The tree `root` can be obtained from the locally maintained Merkle tree.
The proof generation results in the following data items which are encoded inside the `proof`:
The preceding values as well as the tree `root` (based on which the proof is generated) are encoded inside the `proof` as `|zkSNARKs<256>|root<32>|epoch<32>|share_x<32>|share_y<32>|nullifier<32>|`.
The numbers enclosed in angle brackets indicate the bit length of the corresponding data item.
The tuple of (`nullifier`, `share_x`, `share_y`) can be seen as partial disclosure of peer's `sk` for the intended `epoch`.
Given two such tuples with identical `nullifier` but distinct `share_x`, `share_y` results in full disclosure of peer's `sk` and hence burning the associated deposit.
Note that the `nullifier` is a deterministic value derived from `sk` and `epoch` therefore any two messages issued by the same peer (i.e., sing the same `sk`) for the same `epoch` are guaranteed to have identical `nullifier`s.
Note that the `authPath` of each peer depends on the current status of the registration tree (hence changes when new peers register).
As such, it is recommended (and necessary for anonymity) that the publisher updates her `authPath` based on the latest status of the group and attempts the proof using her updated `authPath`.
Upon the receipt of a PubSub message, the routing peer needs to extract and parse the `proof` from the `data` field.
If the `epoch` attached to the message has a non-reasonable gap (TODO: the gap should be defined) with the routing peer's current `epoch` then the message must be dropped (this is to prevent a newly registered peer spamming the system by messaging for all the past epochs).
Furthermore, the routing peers MUST check whether the `proof` is valid and the message is not spam.
If both checks are passed successfully, then the message is relayed.
If `proof` is invalid then the message is dropped.
If spamming is detected, the publishing peer gets slashed.
An overview of routing procedure is depicted in Figure 2.
In order to enable local spam detection and slashing, routing peers MUST record the `nullifier`, `share_x`, and `share_y` of any incoming message conditioned that it is not spam and has valid proof.
To do so, the peer should follow the following steps.
1. The routing peer first verifies the `zkSNARKs` and drops the message if not verified.
1. If such message exists and its `share_x` and `share_y` components are different from the incoming message, then slashing takes place (if the `share_x` and `share_y` fields of the previously relayed message is identical to the incoming message, then the message is a duplicate and shall be dropped).
<!-- TODO: may consider [validator functions](https://github.com/libp2p/specs/tree/master/pubsub#topic-validation) or [extended validators](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.1.md#extended-validators) for the spam detection -->