From 0d60b6fb3c89f349125760ff32bd737b15d793e1 Mon Sep 17 00:00:00 2001 From: Sergei Tikhomirov Date: Mon, 19 Aug 2024 16:39:27 +0200 Subject: [PATCH] style edits --- standards/core/rln-contract.md | 223 +++++++++++++++++---------------- 1 file changed, 116 insertions(+), 107 deletions(-) diff --git a/standards/core/rln-contract.md b/standards/core/rln-contract.md index 4c3043a..b0a1d93 100644 --- a/standards/core/rln-contract.md +++ b/standards/core/rln-contract.md @@ -9,15 +9,15 @@ contributors: ## Abstract -This document describes membership management for the RLN smart contract, in particular: +This document describes membership management within the RLN smart contract, specifically addressing: - membership-related contract functionality; -- suggested parameters valued for the initial mainnet deployment; +- suggested parameter values for the initial mainnet deployment; - contract governance and upgradability. -This document currently only considers membership-related functionality. -It might later evolve into a full-fledged contract specification. +Currently, this document focuses solely on membership-related functionality. +It might later evolve into a comprehensive contract specification. -RLN is only deployed on Sepolia testnet ([source code](https://github.com/waku-org/waku-rlnv2-contract/blob/main/src/WakuRlnV2.sol)) as of August 2024. +As of August 2024, RLN is deployed only on Sepolia testnet ([source code](https://github.com/waku-org/waku-rlnv2-contract/blob/main/src/WakuRlnV2.sol)). This document aims to outline the path to its mainnet deployment. ## Syntax @@ -26,16 +26,16 @@ The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL ## Background -Rate-Limiting Nullifier (RLN) is a ZK-based gadget used for privacy-preserving rate limiting in Waku. -The RLN smart contract is the core element of RLN architecture. -The smart contract stores the RLN tree that contains all currently existing memberships. +Rate-Limiting Nullifier (RLN) is a Zero-Knowledge (ZK) based gadget used for privacy-preserving rate limiting in Waku. +The RLN smart contract (referred to as "the contract" hereinafter) is the central component of the RLN architecture. +The contract stores the RLN tree, which contains all current memberships. Users interact with the contract to manage their memberships -and to get the necessary data for proof generation and verification. +and obtain the necessary data for proof generation and verification. -Sending messages is handled by Waku RLN Relay nodes. -To send a message, the sender MUST prove its validity in terms of RLN. +Message transmission is handled by Waku RLN Relay nodes. +The sender of a message MUST prove its validity according to RLN requirements. RLN Relay nodes MUST NOT relay invalid messages. -See [17/WAKU2-RLN-RELAY](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/17/rln-relay.md) for the full specification of RLN Relay. +For the full specification of RLN Relay, see See [17/WAKU2-RLN-RELAY](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/17/rln-relay.md). ## Contract overview @@ -44,23 +44,25 @@ The contract MUST provide the following functionalities: - extend a membership; - withdraw a deposit. -A membership _holder_ is the entity that controls the secret of the respective RLN commitment. -A membership _keeper_ is the entity that controls the Ethereum address that registered that membership. -The holder and the keeper MAY differ for the same membership. -The contract SHOULD only distinguish between the keeper and non-keepers when authorizing membership-related requests. +A membership _holder_ is the entity that controls the secret associated with the respective RLN commitment. +A membership _keeper_ is the entity that controls the Ethereum address used to register that membership. +The holder and the keeper MAY be different entities for the same membership. +When authorizing membership-related requests, +the contract SHOULD distinguish between the keeper and non-keepers, +and MAY also use additional criteria. Contract parameters and their RECOMMENDED values for the initial mainnet deployment are as follows: -| Parameter | Symbol | Value | Units | -| ------------------------------------------- | --------- | -------- | -------------------- | -| Epoch length | `epoch` | `10` | minutes | -| Maximum total rate limit of all memberships | `R_{max}` | `160000` | messages per `epoch` | -| Minimal rate limit of one membership | `r_{min}` | `20` | messages per `epoch` | -| Maximum rate limit of one membership | `r_{max}` | `600` | messages per `epoch` | -| Membership price for `1` message per epoch | `p_u` | `0.05` | `USD` | -| Membership expiration term | `T` | `180` | days | -| Membership grace period | `G` | `30` | days | -| Accepted tokens | | `DAI` | | +| Parameter | Symbol | Value | Units | +| ------------------------------------------------------- | --------- | -------- | -------------------- | +| Epoch length | `epoch` | `10` | minutes | +| Maximum total rate limit of all memberships in the tree | `R_{max}` | `160000` | messages per `epoch` | +| Minimum rate limit of one membership | `r_{min}` | `20` | messages per `epoch` | +| Maximum rate limit of one membership | `r_{max}` | `600` | messages per `epoch` | +| Membership price for `1` message per epoch | `p_u` | `0.05` | `USD` | +| Membership expiration term | `T` | `180` | days | +| Membership grace period | `G` | `30` | days | +| Accepted tokens | | `DAI` | | The pricing function SHOULD be linear in the rate limit per epoch. @@ -89,10 +91,10 @@ graph TD; State updates triggered by a transaction (e.g., from _GracePeriod_ to _Active_ as a result of `extend`) MUST be applied immediately. State updates defined by time progression (e.g., from _GracePeriod_ to _Expired_ after time `G`) MAY be applied lazily. -When providing any membership-specific functionality, the contract MUST: -- check whether the state of the membership involved is up-to-date; +When handling a membership-specific transaction, the contract MUST: +- check whether the state of the involved membership is up-to-date; - if necessary, update the membership state; -- process the transaction in accordance with the up-to-date membership state. +- process the transaction in accordance with the updated membership state. Memberships MUST be included in the RLN tree according to the following table: @@ -106,14 +108,14 @@ Memberships MUST be included in the RLN tree according to the following table: Memberships MUST NOT be transferable. A user MAY use one Ethereum address to manage multiple memberships. -A user MAY use one Waku node to manage multiple memberships. [^1] +A user MAY use one Waku node[^1] to manage multiple memberships. [^1]: No Waku implementation supports managing multiple memberships from one node (as of August 2024). ## Contract functionalities -Availability of membership-specific functionalities MUST be as follows: +Availability of membership-specific functionalities[^2] MUST be as follows: | | Active | GracePeriod | Expired | ErasedAwaitsWithdrawal | Erased | | --------------------- | ------ | ----------- | ------- | ---------------------- | ------ | @@ -121,48 +123,45 @@ Availability of membership-specific functionalities MUST be as follows: | Extend the membership | No | Yes | No | No | No | | Withdraw the deposit | No | Yes | Yes | Yes | No | -Sending a message is included here for completeness, -although it is part of the RLN Relay protocol and not the RLN contract. +[^2]: Sending a message is included here for completeness, although it is part of the RLN Relay protocol and not the contract. ### Register a membership Membership registration is subject to the following conditions: -- if there are _Expired_ memberships in the RLN tree, the new membership MUST overwrite an _Expired_ membership; -- the new membership SHOULD overwrite the membership that had been _Expired_ for the longest time; -- if a new membership A overwrites an _Expired_ membership B: +- If there are _Expired_ memberships in the RLN tree, the new membership MUST overwrite an _Expired_ membership. +- The new membership SHOULD overwrite the membership that has been _Expired_ for the longest time. +- If a new membership A overwrites an _Expired_ membership B: - membership B MUST become _ErasedAwaitsWithdrawal_; - the current total rate limit MUST be decremented by the rate limit of membership B; - - the contract MUST take all necessary steps to ensure that the keeper of membership B can withdraw their deposit later; -- registration MUST fail if the total rate limit of _Active_, _GracePeriod_, and _Expired_ memberships, including the one being created, would exceed `R_{max}`; -- registration MUST fail if the requested rate limit for a new membership is lower than `r_{min}` or higher than `r_{max}`; -- the user MUST lock-up a deposit to register a membership; -- the user MUST specify the rate limit of the new membership[^2]; -- the size of the deposit MUST depend on the requested rate limit; -- in case of a successful registration: + - the contract MUST take all necessary steps to ensure that the keeper of membership B can withdraw their deposit later. +- Registration MUST fail if the total rate limit of _Active_, _GracePeriod_, and _Expired_ memberships, including the one being created, would exceed `R_{max}`. +- Registration MUST fail if the requested rate limit for a new membership is lower than `r_{min}` or higher than `r_{max}`. +- The keeper MUST lock up a deposit to register a membership. +- The keeper MUST specify the rate limit[^3] of a membership at registration time. +- The size of the deposit MUST depend on the specified rate limit. +- In case of a successful registration: - the new membership MUST become _Active_; - - the current total rate limit MUST be incremented by the rate limit of the new membership; -- a newly created membership MUST have an expiration time `T` and a grace period `G`. + - the current total rate limit MUST be incremented by the rate limit of the new membership. +- A membership MUST have an expiration time `T` and a grace period `G`. -[^2]: A user-facing application SHOULD suggest default values for rate limits for the user. +[^3]: A user-facing application SHOULD suggest default rate limits to the keeper (see Implementation Suggestions). ### Extend a membership Extending a membership is subject to the following conditions: -- extension MUST fail if the membership is in any state other than _GracePeriod_; -- the membership keeper MUST be able to extend their membership; -- any user except the membership keeper MUST NOT be able to extend a membership; -- after a successful extension, the membership MUST become _Active_. - - +- The extension MUST fail if the membership is in any state other than _GracePeriod_. +- The membership keeper MUST be able to extend their membership. +- Any user other than the membership keeper MUST NOT be able to extend a membership. +- After a successful extension, the membership MUST become _Active_. ### Withdraw the deposit Deposit withdrawal is subject to the following conditions: -- the membership keeper MUST be able to withdraw their deposit; -- any user except the membership keeper MUST NOT be able to withdraw its deposit; -- a deposit MUST be withdrawn in full; -- a withdrawal MUST fail if the membership is not in _GracePeriod_, _Expired_, or _ErasedAwaitsWithdrawal_; -- a membership MUST become _Erased_ after withdrawal. +- The membership keeper MUST be able to withdraw their deposit. +- Any user other than the membership keeper MUST NOT be able to withdraw its deposit. +- A deposit MUST be withdrawn in full. +- A withdrawal MUST fail if the membership is not in _GracePeriod_, _Expired_, or _ErasedAwaitsWithdrawal_. +- A membership MUST become _Erased_ after withdrawal. ## Governance and upgradability @@ -173,12 +172,15 @@ The _Owner_ MUST be able to pause any of the following contract functionalities: - extend a membership; - withdraw a deposit. -At some point, the _Owner_ SHOULD renounce their privileges, and the contract MUST become immutable. -Further upgrades, if necessary, SHOULD be done by deploying a new contract and migrating the membership set. +At some point, the _Owner_ SHOULD renounce their privileges, +and the contract MUST become immutable. +If further upgrades are necessary, +a new contract SHOULD be deployed, +and the membership set SHOULD be migrated. ## Implementation Suggestions -User-facing application SHOULD suggest one or a few rate limits (tiers) to simplify their users' choice among the following RECOMMENDED rate limits: +User-facing applications SHOULD suggest one or more rate limits (tiers) to simplify user selection among the following RECOMMENDED options: - `20` messages per epoch as low-tier; - `200` messages per epoch as mid-tier; - `600` messages per epoch as high-tier. @@ -190,100 +192,107 @@ and notify the user when their membership is about to expire. ### Why can't I withdraw a deposit from an _Active_ membership? -The rationale for this limitation is to prevent an undesirable usage pattern where users make deposits and withdrawals in short succession. -Such pattern may lead to network instability and should be carefully studied if seen as desirable. +The rationale for this limitation is to prevent a usage pattern where users make deposits and withdrawals in quick succession. +Such a pattern could lead to network instability and should be carefully considered if deemed desirable. ### Why can't I extend an _Active_ membership? Memberships can only be extended during _GracePeriod_. -We do not allow extending an _Active_ membership. -The rationale is that if the contract _Owner_ changes some contract parameters (e.g., for security purposes), -users with extended memberships will not be affected by the changes for a long time. +Extending an _Active_ membership is not allowed. +The rationale is to make possible parameter changes that the contract _Owner_ might make (e.g., for security reasons) applicable to most memberships. ### What if I don't extend my membership within its _GracePeriod_? -The user who does not extend their _GracePeriod_ membership, -assume the risk of their _Expired_ membership being overwritten. -We expect, generally, that a user would not want to take that risk -and would either extend their membership or withdraw their deposit. +If a user does not extend their membership during the _GracePeriod_, +they risk having their _Expired_ membership overwritten. +Generally, users are expected to either extend their membership or withdraw their deposit to avoid this risk. ### Can I send messages when my membership is _Expired_? -An _Expired_ membership allows sending messages for some time. -Sending messages is managed by RLN Relay nodes. -The RLN proof that message senders provide to RLN Relay nodes doesn't prove the state of that membership. +An _Expired_ membership allows sending messages for a certain period. +The RLN proof that message senders provide to RLN Relay nodes does not prove the state of the membership, +only its inclusion in the tree. -_Expired_ memberships are not erased from the tree proactively. -An _Expired_ membership is only erased when either a new membership overwrites it, -or when its deposit is withdrawn. -After a membership is erased, it can no longer be used for sending messages. +_Expired_ memberships are not proactively erased from the tree. +An _Expired_ membership is erased only when a new membership overwrites it or when its deposit is withdrawn. +Once erased (i.e., _Erased_ or _ErasedAwaitsWithdrawal_), the membership can no longer be used to send messages. ### Will my deposit be slashed if I exceed the rate limit? -This specification does not involve slashing. -The aim of the deposit initially is to protect the network from denial-of-service attacks with bandwidth capping. +This specification does not include slashing. +The deposit's current purpose is purely to protect the network from denial-of-service attacks through bandwidth capping. -### Do I need an extra deposit to extend a membership? +### Do I need an extra deposit to extend my membership? Membership extension requires no additional deposit. -The opportunity cost of locked-up capital plus gas fees for extension transactions make extensions non-free, which is sufficient for the initial mainnet deployment. +The opportunity cost of locked-up capital and gas fees for extension transactions make extensions non-free, +which is sufficient for the initial mainnet deployment. ### Why this particular epoch length? -Epoch length is a global parameter set in the smart contract. +Epoch length is a global parameter defined in the contract. Rate limits are defined in terms of the maximum allowed messages per epoch. -There is a trade-off between short and long epochs. -We chose an epoch length of `10` minutes as a reasonable middle-ground. -On the one hand, longer epochs allow for better accommodating short-term usage peaks. -On the other hand, long epochs increases memory requirements for RLN Relay nodes. +There is a trade-off between short and long epochs. +Longer epochs accommodate short-term usage peaks better, +but they increase memory requirements for RLN Relay nodes. +An epoch length of `10` minutes was chosen as a reasonable middle ground. Each message contains a nullifier that proves its validity in terms of RLN. -Each RLN Relay node must store in memory a nullifier log for the current epoch. -Each nullifier plus metadata is `128` bytes (per message). -With a `10`-minute epoch, one high-tier user with a `1` message per second rate limit generates up to `600 * 128 / 1024 = 75 KiB` of nullifier log data per epoch. -This corresponds to: -- for 1000 users: approximately `73 MiB`; -- for 10 thousand users: approximately `732 MiB`. +Each RLN Relay node must store a nullifier log for the current epoch in memory. +A nullifier plus metadata is `128` bytes per message. +With a `10`-minute epoch, a high-tier user with a `1` message per second rate limit generates up to `600 * 128 / 1024 = 75 KiB` of nullifier log data per epoch. +This equates to, approximately: +- `73 MiB` for 1000 users; +- `732 MiB` for 10 thousand users. ### Why is there a cap on the total rate limit? Total network bandwidth is a limited resource. -We want to cap the total rate limit, at least in the initial mainnet deployment, to avoid overstretching the network's capabilities. +To avoid overstretching the network's capabilities for the initial mainnet deployment, +we define a cap `R_{max}` on the total rate limit. -### Why is there a minimal rate limit? +### Why is there a minimum rate limit? -The minimal rate limit prevents an attack where someone registers a large number of memberships with a tiny rate limit each, causing the RLN tree to contain too many elements. +The minimum rate limit `r_{min}` prevents an attack where a large number of tiny memberships cause RLN tree bloat. + +### Why is there a maximum rate limit? + +The maximum rate limit `r_{max}` prevents any single actor from consuming an excessive portion of the total available rate limit. + +However, it is still possible for an attacker to register multiple Ethereum addresses, +and occupy a significant portion of the total rate limit through several memberships. ### Are there bulk discounts for high-rate memberships? -For the initial mainnet deployment, there are no bulk discounts. +For the initial mainnet deployment, no bulk discounts are offered. Membership price is linearly proportional to its rate limit. We choose this pricing scheme for simplicity. -Finding a pricing scheme with the right trade-off remains subject for future work, as -high-rate memberships are arguably more efficient but can incentivize centralization. +Future work may explore alternative pricing schemes that balance efficiency with centralization risk. ### Why only accept DAI? When choosing a token to accept, we considered the following criteria: - a stablecoin, as USD-denominated pricing is familiar for users and requires no oracle; -- popular, high liquidity; -- preferably decentralized; -- with a reasonably good anti-censorship track record. +- popular with high liquidity; +- decentralized; +- reasonably good censorship-resistance. Based on these criteria, we chose DAI for the initial mainnet deployment. Other tokens may be added in the future. ## Security / Privacy Considerations -Issuing membership-specific transactions (e.g., membership extension and deposit withdrawal) publicly links it to an Ethereum address. -Note that this does not degrade the privacy of the relayed messages, -as message validation doesn't require the sender to disclose which membership they hold. +Issuing membership-specific transactions, +such as membership extensions and deposit withdrawals, +publicly associates a membership with an Ethereum address. +However, this association does not compromise the privacy of the relayed messages, +as the protocol does not require the sender to disclose their specific membership to RLN Relay nodes. -To produce an RLN proof, a message sender must obtain a Merkle proof that their membership belongs to the RLN tree. -One way to obtain this proof is to request it from the smart contract itself. -Requesting a proof through a third-party RPC provider may endanger the sender's privacy. -The provider would be able to link the requester's Ethereum address and the RLN membership with the corresponding API key. +To generate an RLN proof, a message sender must obtain a Merkle proof confirming that their membership belongs to the RLN tree. +This proof can be requested directly from the contract. +Requesting the proof through a third-party RPC provider could compromise the sender's privacy, +as the provider might link the requester's Ethereum address, their RLN membership, and the corresponding API key. ## Copyright