Skip to content

Commit

Permalink
Custom witness with onchain Merkle proof (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
alrevuelta authored Apr 23, 2024
1 parent 23a7f49 commit 9fef5ea
Show file tree
Hide file tree
Showing 7 changed files with 405 additions and 174 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
main
**/.DS_Store
**.json
48 changes: 29 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,19 @@
# go-waku-light

This repo contains a proof of concept of a `waku` light client, integrating [this](https://github.com/vacp2p/rln-contract/pull/31) modification in the RLN contract, which allows having the whole membership set + Merkle root on-chain. This makes light clients even lighter.
This repo contains a proof of concept for a `waku` light client, integrating [this](https://github.com/vacp2p/rln-contract/pull/31) modification of the RLN contract. It allows:
* Faster sync time. Uses `GetCommitments` instead of fetching events.
* Getting the Merkle root directly from the contract. No need to sync the whole tree.
* Getting the Merkle proof for any leaf directly from the contract. Not need to sync the whole tree.

For context, RLN is a decentralized rate-limiting protocol, that allows setting a limit on the number of messages sent by each entity, using zero-knowledge proofs. Said proofs prove that i) the member is whitelisted, without revealing its index, and ii) no more than 1 message is sent every epoch, which prevents double signaling.

The main motivation is to showcase how [this](https://github.com/vacp2p/rln-contract/pull/31) modification can help light clients become lighter. It makes proof generation and verification easier:
* Proof verification: Only requires the Merkle root, which is now available on-chain and can be fetched with a simple call. Before, one had to sync the whole Merkle tree with emitted events, and keep a local copy of it.
* Proof generation: Requires the whole Merkle tree, which can be synced faster since this modification stores all the leaves in the contract. This approach is faster than syncing events, with the con of spending more gas on membership registration.
* Proof generation: Generating an RLN proof requires the Merkle proof of the leaf generating it. With this modification, said Merkle proof can be obtained directly from the contract.

Notes:
* The new [contract](https://github.com/vacp2p/rln-contract/pull/31) uses a [BinaryIMT](https://github.com/privacy-scaling-explorations/zk-kit/blob/main/packages/imt.sol/contracts/BinaryIMT.sol).
* It is deployed in Polygon Layer 2 zkEVM, [see](https://testnet-zkevm.polygonscan.com/address/0x16aBFfCAB50E8D1ff5c22b118Be5c56F801Dce54).

This repo provides the following functionalities:
* Register an RLN membership in the contract in Layer 2 (Polygon zkEVM)
* Listen to new membership addition
* Get on-chain Merkle root
* Locally sync the membership Merkle tree (no need to sync events as before)
* Generate RLN proofs for a message
* Verify RLN proofs against the contract Merkle root.
* Deployed in Polygon Layer 2 zkEVM, [see](https://cardona-zkevm.polygonscan.com/address/0x16abffcab50e8d1ff5c22b118be5c56f801dce54).
* This repo provides a simple CLI tool to showcase the functionalities.

## Usage

Expand All @@ -37,22 +32,37 @@ Register a new membership. You must provide a valid Polygon zkEVM account, see [
./main register --priv-key=REPLACE_YOUR_PRIV_KEY
```

Fetches and logs the latest Merkle root of the tree, using the contract as a source.
Fetches and logs the latest Merkle root and Merkle proof of the tree, using the contract as a source. Set `leaf-index` to your leaf index.
```
./main onchain-root
./main onchain-merkle-proof --leaf-index=1
```

Syncs the Merkle tree from the contract creating a local tree. The `chunk-size` indicates how many memberships are fetched at once. If too big, the RPC provider may error. Merkle proof can be locally computed, provide your `leaf-index`. Both `onchain` and `local` results should match.
```
./main local-root --chunk-size=500
./main local-merkle-proof --chunk-size=500 --leaf-index=1
```

Syncs the Merkle tree from the contract. The `chunk-size` indicates how many memberships are fetched at once. If too big, the RPC provider may error.
Generates the RLN proof using a given membership, see the previous step. The proof is stored in a `.json` file. Message and epoch are hardcoded for simplicity. Note that the RLN can be generated `onchain` (which doesn't require to locally sync the tree since it uses the contract) and `local` (which syncs the tree locally).
```
./main sync-tree --chunk-size=500
./main onchain-generate-rln-proof --membership-file=membership_xxx.json
./main local-generate-rln-proof --membership-file=membership_xxx.json --chunk-size=500
```

Generates a proof using a given membership. The proof is stored in a `.json` file.
Any RLN proof can be verified against the smart contract Merkle root.
```
./main generate-proof --membership-file=membership_xxx.json
./main verify-rln-proof --proof-file=proof_xxx.json
```

Verifies a given proof against the smart contract Merkle root.

## Advanced

The `contract/contract.go` can be updated if the abi is changed as follows:

```
./main verify-proof --proof-file=proof_xxx.json
git clone https://github.com/ethereum/go-ethereum.git
cd go-ethereum
go build ./cmd/abigen
./abigen --abi=../go-waku-light/contract/abi.abi --pkg=contract --out=../go-waku-light/contract/contract.go
```
2 changes: 1 addition & 1 deletion contract/abi.abi
Original file line number Diff line number Diff line change
@@ -1 +1 @@
[{"inputs":[{"internalType":"uint256","name":"membershipDeposit","type":"uint256"},{"internalType":"uint256","name":"depth","type":"uint256"},{"internalType":"address","name":"_verifier","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"DuplicateIdCommitment","type":"error"},{"inputs":[],"name":"FullTree","type":"error"},{"inputs":[],"name":"InsufficientContractBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"required","type":"uint256"},{"internalType":"uint256","name":"provided","type":"uint256"}],"name":"InsufficientDeposit","type":"error"},{"inputs":[],"name":"InsufficientWithdrawalBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"idCommitment","type":"uint256"}],"name":"InvalidIdCommitment","type":"error"},{"inputs":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"endIndex","type":"uint256"}],"name":"InvalidPaginationQuery","type":"error"},{"inputs":[],"name":"InvalidProof","type":"error"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"InvalidReceiverAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"idCommitment","type":"uint256"}],"name":"MemberHasNoStake","type":"error"},{"inputs":[{"internalType":"uint256","name":"idCommitment","type":"uint256"}],"name":"MemberNotRegistered","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"idCommitment","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"}],"name":"MemberRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"idCommitment","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"}],"name":"MemberWithdrawn","type":"event"},{"inputs":[],"name":"DEPTH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MEMBERSHIP_DEPOSIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"Q","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SET_SIZE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deployedBlockNumber","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"endIndex","type":"uint256"}],"name":"getCommitments","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"idCommitmentIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"imtData","outputs":[{"internalType":"uint256","name":"depth","type":"uint256"},{"internalType":"uint256","name":"root","type":"uint256"},{"internalType":"uint256","name":"numberOfLeaves","type":"uint256"},{"internalType":"bool","name":"useDefaultZeroes","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"indexToCommitment","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"idCommitment","type":"uint256"}],"name":"isValidCommitment","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"memberExists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"members","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"idCommitment","type":"uint256"}],"name":"register","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"root","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"idCommitment","type":"uint256"},{"internalType":"address payable","name":"receiver","type":"address"},{"internalType":"uint256[8]","name":"proof","type":"uint256[8]"}],"name":"slash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"stakedAmounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"verifier","outputs":[{"internalType":"contract IVerifier","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"withdrawalBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
[{"inputs":[{"internalType":"uint256","name":"membershipDeposit","type":"uint256"},{"internalType":"uint256","name":"depth","type":"uint256"},{"internalType":"address","name":"_verifier","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"DuplicateIdCommitment","type":"error"},{"inputs":[],"name":"FullTree","type":"error"},{"inputs":[],"name":"InsufficientContractBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"required","type":"uint256"},{"internalType":"uint256","name":"provided","type":"uint256"}],"name":"InsufficientDeposit","type":"error"},{"inputs":[],"name":"InsufficientWithdrawalBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"idCommitment","type":"uint256"}],"name":"InvalidIdCommitment","type":"error"},{"inputs":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"endIndex","type":"uint256"}],"name":"InvalidPaginationQuery","type":"error"},{"inputs":[],"name":"InvalidProof","type":"error"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"InvalidReceiverAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"idCommitment","type":"uint256"}],"name":"MemberHasNoStake","type":"error"},{"inputs":[{"internalType":"uint256","name":"idCommitment","type":"uint256"}],"name":"MemberNotRegistered","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"idCommitment","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"}],"name":"MemberRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"idCommitment","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"}],"name":"MemberWithdrawn","type":"event"},{"inputs":[],"name":"DEPTH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MEMBERSHIP_DEPOSIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"Q","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SET_SIZE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deployedBlockNumber","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"endIndex","type":"uint256"}],"name":"getCommitments","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"idCommitmentIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"imtData","outputs":[{"internalType":"uint40","name":"maxIndex","type":"uint40"},{"internalType":"uint40","name":"numberOfLeaves","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"indexToCommitment","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"idCommitment","type":"uint256"}],"name":"isValidCommitment","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"memberExists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"members","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint40","name":"index","type":"uint40"}],"name":"merkleProofElements","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"idCommitment","type":"uint256"}],"name":"register","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"root","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"idCommitment","type":"uint256"},{"internalType":"address payable","name":"receiver","type":"address"},{"internalType":"uint256[8]","name":"proof","type":"uint256[8]"}],"name":"slash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"stakedAmounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"verifier","outputs":[{"internalType":"contract IVerifier","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"withdrawalBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Loading

0 comments on commit 9fef5ea

Please sign in to comment.