---
# System prepended metadata

title: Onboarding flow research topics

---

# Onboarding flow research topics

## 2023-12-14

### The state of JS RLN libraries


1. This is one I found earlier and it is referenced everywhere: https://github.com/Rate-Limiting-Nullifier/rln-contract

I don't completely understand this, it associates an address with the identityCommitment and also somehow assumes that the identityCommitment is known when verifying the proof: https://github.com/Rate-Limiting-Nullifier/rln-contract/blob/23f8ee13db1d9b41b5c1c0a2b154a8e4fbf4c2f3/src/RLN.sol#L125

Like this it seems to be losing the privacy aspects that we are looking for and also questions the point of using ZKPs.

2. Then here is what Waku uses: https://github.com/waku-org/waku-rln-contract

This seems to be a fork of [vacp2p/rln-contract](https://github.com/vacp2p/rln-contract) and it looks like it is  Work-in-progress, and it throws `NotImplemented` errors from many functions.

3. The https://github.com/vacp2p/rln-contract seems to be a fork of the 1.

This fixes some of the issues with 1st (for example the registration does not require an address) and looks the most promising from the three.


### Spam control in CypherCity

tags: spam, semaphore, cyphercity, RLN

Attila: after building a [proof-of-concept smart contract](https://github.com/logos-innovation-lab/cyphercity-contract/pull/1) based on Semaphore, I realized that for the CypherCity concept (completely anonymous semi-public forum) we will need a way to control spam. 

With Semaphore the sender of a message cannot be identified and that means that there is no way to punish the sender if they are spamming. It is possible to add some voting mechanism for the messages themselves, but an effective spammer would be able to simply outweigh the  humans trying to keep up the noise/signal ratio.

Another potential solution I considered is to limit the amount of messages to be sent by introducing some kind of epoch mechanism, make the `externalNullifier` derived from the epoch and only allow a certain number of messages in a certain epoch. This could work but because the verification (and therefore the counting of messages)  happen in the client side, a spammer could still overwhelm the group with messages and go without being punished.

Then I was looking into RLN which solves this problem in an elegant way, by adding more fields to the proof attached to each messages. The added fields shares parts of the sender's private key using [Shamir's secret sharing](https://en.wikipedia.org/wiki/Shamir's_secret_sharing) and therefore someone sending too many messages in one epoch risks revealing their own private key and therefore makes other peers eligible for taking their stakes ("slashing").

I found a [JS implementation](https://github.com/Rate-Limiting-Nullifier/rlnjs) that Waku also uses, which is similar to Semaphore, but different enough to be incompatible, so we will need to build another PoC with that.

An interesting alternative could be also to require either the messages or just the proofs to be posted on the blockchain, assuming there is a privacy pool and low-cost transactions. 

### Privacy pool open questions

1. How can someone add funds to the privacy pool in a privacy preserving way?

So far it seems everyone is using a relay for that. Relying on a single relay implies trust and is a single-point of failure and therefore easily can be censored. It would be good to come up with alternatives for evaluation.

2. How to denominate the funds so that they can be used in a flexible way?

Usually privacy pools helds funds in multiplier of 10s (e.g. 1 ETH, 10 ETH, 100 ETH). Most likely we need smaller denominations to be able to do one-off transactions, but also bigger ones, so that you don't need to bundle many small transactions if you want to send a bigger amount. Maybe it's a good idea to predefine the invite value as well.

3. Interactivity

Privacy pools often require a certain amount of deposit in a certain denomination so that a level of anonymity can be provided. This does not work well with interactive use-cases such as the invite flow when someone scans the other person's QR code. We can think of prefunded wallets from the pool that you can hand out to someone else instantly when inviting.

## 2023-12-11

### Semaphore send & receive flow

Attila: Here is my current idea about the semaphore send/recieve flow. We would only use the contract for maintaining the membership and not for sending messages. In order to avoid keeping the nullifiers forever I propose an alternative. We keep track of a counter that is increased every time the merkleTreeRoot changes (let's call this simply a counter)

For sending:

- First the onchain merkleTreeRoot needs to be checked and updated (along with the  counter and the members) if necessary.
- We will use the counter as the `externalNullifier`. That way we may keep track of nullifierHashes for the last X counter items and we don't need to keep all of them, because we can simply discard messages that have `externalNullifier < counter - X`
- Generate a proof and attach to the message. We can use the messageId (which is a hash of the message according to https://rfc.vac.dev/spec/14/#deterministic-message-hashing) as the signal


For receiving:

- I think it would be less than optimal to check the merkleTreeRoot onchain every time a message is received
- Instead we can just compare with the current merkleTreeRoot and counter. If it is the same then we can move on. If it is not we can check if the externalNullifier is in the range with the equation above. If it is in the past but not in the past range then we can discard as invalid. If it is in the future we need to update the `merkleTreeRoot` and counter from the blockchain (fetching the members is optional).
- Then we can check if we have already seen the message in the nullifierHashes
- Proof verification: first check if the signal is indeed the message hash. Then verify the attached proof. If it is verified the message can be added to babbles.
