Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added guides for on-chain validation of ZK Passport proofs #60

Merged
merged 9 commits into from
Apr 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added
- ZK Passport guide for on-chain verification;
- Guide for setting up a verificator-svc instance;
- Guide for setting up state replication for ZK Passport;

## [5.6.0] - 2025-03-28
### Removed
- ZK Socials
Expand Down
186 changes: 186 additions & 0 deletions docs/zk-passport/guide-on-chain-verification.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
---
description: Use ZK Passport to verify users on-chain without revealing private data. Learn how to implement the verification process step-by-step.
sidebar_label: "Guide: on-chain verification"
---

import OutLink from "@site/src/components/OutLink";
import IdealImage from '@site/src/components/IdealImage';

# Guide: Setting up on-chain user verification with ZK Passport

This tutorial walks you through the process of setting up on-chain verification of ZK Passport proofs on-chain. By the end of this tutorial, you will have:

1. Ensure that you have all the necessary components in place to verify ZK Passport proofs on your chain.
1. Deployed the **Verificator** contract on your chain to handle proof verification.
1. Integrated verification logic in your own contract to validate proof public signals.

>TODO: add step for setting up the front-end with our new SDK

## Prerequisites

- In case you are using an EVM-compatible chain other than Rarimo's L2, you'll need to to set up the ZK Passport Registry state replication as described in [Setting up cross-chain verification](/zk-passport/guide-setting-up-cross-chain-replication).
- Access to the [`verificator-svc`](https://github.com/rarimo) service for retrieving proof parameters. You can use the public instance of `verificator-svc` <OutLink href="https://api.app.rarime.com/">https://api.app.rarime.com/</OutLink> for testing, but it's recommended to deploy your own instance for production use, as described in [Setting up verificator-svc](/zk-passport/guide-setting-up-verificator-svc).

## Step 1: Deploy the Verificator smart contract

>TODO: put this contract into an npm package?
>TODO: guide to customizing the query params

The **Verificator** contract is responsible for verifying the ZK proofs on-chain. This contract often comes with a precompiled ZK circuit.

1. Obtain the `Verificator` contract <OutLink href="https://github.com/rarimo/passport-voting-contracts/blob/4cccd0ca8613330c4af68d8e0f7ca46bd3b68ac9/contracts/voting/verifiers/BioPassportVotingVerifier.sol">source code</OutLink> and add it to your project.

```solidity
contract Verificator {
function verifyProof(
uint[2] calldata _pA,
uint[2][2] calldata _pB,
uint[2] calldata _pC,
uint[23] calldata _pubSignals
) public view returns (bool) {
...
}
}
```
1. Deploy it to your chain and record the address of the newly deployed `Verificator`. You will use this address in your other contracts to verify proofs.

## Step 2: Integrate Proof Verification in Your Smart Contract

Once your chain is replicating ZK Registry state and you have a deployed `Verificator` contract, you can add ZK proof checks to your own contract logic.

### A. Collect public signals and proof from `verificator-svc`

When a user scans a QR code and submits a proof:

1. Your DApp calls the <OutLink href="https://rarimo.github.io/verificator-svc/#tag/User-verification/operation/getProof">`getProof`</OutLink> endpoint from `verificator-svc`.
1. Receive both `pubSignals` and the `proof` from the service:

```json
{
"pubSignals": ["12345", "67890", "..."],
"proof": "0xabc123..."
}
```

1. Pass the `pubSignals` as calldata to the `verifyProof()` method in the smart contract along the `proof`.

```solidity
pragma solidity ^0.8.0;

interface IVerificator {
function verifyProof(
uint256[] calldata pubSignals,
bytes calldata proof
) external view returns (bool);
}

contract MyPassportContract {
IVerificator public verificator;

constructor(address _verificator) {
// this is the address of the deployed Verificator contract from step #1
verificator = IVerificator(_verificator);
}

function verifyPassportProof(
uint256[] calldata pubSignals,
bytes calldata proof
) external {
// highlight-start
bool isValid = verificator.verifyProof(pubSignals, proof);
require(isValid, "Passport proof is invalid!");
// highlight-end

// If the proof is valid, proceed with your logic
// e.g., granting access, minting an NFT, etc.
}
}
```

The critical part is:

```solidity
bool isValid = verificator.verifyProof(pubSignals, proof);
require(isValid, "Passport proof is invalid!");
```

Here, your contract delegates ZK proof validation to the deployed `Verificator` contract.

### B. Manually assemble the pub signals before passing them to the `verifyProof` method

In your smart contract (let's call it `MyPassportContract`), you would do something like this:

```solidity
pragma solidity ^0.8.0;

import {VerifierHelper} from "@solarity/solidity-lib/libs/zkp/snarkjs/VerifierHelper.sol";


interface IVerificator {
function verifyProof(
uint256[] calldata pubSignals,
bytes calldata proof
) external view returns (bool);
}

contract MyPassportContract {
IVerificator public verificator;

constructor(address _verificator) {
// this is the address of the deployed Verificator contract from step #1
verificator = IVerificator(_verificator);
}

function verifyPassportProof(
bytes32 registrationRoot_,
uint256 currentDate_,
uint256 eventId_,
uint256[] memory eventData_,
UserData memory userData_,
VerifierHelper.ProofPoints memory zkPoints_
) external {
// highlight-start
uint256[] memory pubSignals_ = new uint256[](PROOF_SIGNALS_COUNT);

pubSignals_[0] = userData_.nullifier; // output, nullifier
pubSignals_[4] = userData_.citizenship;
pubSignals_[9] = proposalEventId; // input, eventId used to scope your proofs
pubSignals_[10] = uint248(uint256(keccak256(abi.encode(eventData_)))); // input, eventData specific to your DApp
pubSignals_[11] = uint256(registrationRoot_); // input, ZK Registry state root at the moment of proving
pubSignals_[12] = SELECTOR; // input, selector specifying the passport fields to be revealed
pubSignals_[13] = currentDate_; // input, currentDate
pubSignals_[15] = identityCreationTimestampUpperBound; // input, timestampUpperbound
pubSignals_[17] = identityCounterUpperBound; // input
pubSignals_[18] = ZERO_DATE; // input, birthDateLowerbound
pubSignals_[19] = proposalRules_.birthDateUpperbound; // input, birthDateUpperbound
pubSignals_[20] = proposalRules_.expirationDateLowerBound; // input, expirationDateLowerbound
pubSignals_[21] = ZERO_DATE; // input, expirationDateUpperbound

require(votingVerifier.verifyProof(pubSignals_, zkPoints_), "Passport proof is invalid!");
// highlight-end

// If the proof is valid, proceed with your logic
// e.g., granting access, minting an NFT, etc.
}
}
```

Here are a couple of code references that demonstrate how to collect proof public signals and pass them to a verification contract:

- **<OutLink href="https://github.com/rarimo/eip1155-eth/blob/main/contracts/ERC1155ETH.sol#L155">ERC1155ETH.sol</OutLink>**
Shows how a contract gathers public signals and proof parameters before calling `verifyProof`.

- **<OutLink href="https://github.com/rarimo/passport-voting-contracts/blob/master/contracts/voting/BioPassportVoting.sol#L65">BioPassportVoting.sol</OutLink>**
Demonstrates a voting contract that uses ZK proofs for passport-based identity checks.


## Conclusion

With these steps:

1. **Replicate** the ZK Registry state using `RegistrationSMTReplicator`.
2. **Get** proof parameters from `verificator-svc` to collect the ZK Proof in our DApp.
3. **Deploy** your `Verificator` contract to verify the proofs.
4. **Integrate** `verifyProof(...)` calls in your own contract logic.

We've set up on-chain verification of ZK Passport proofs. This allows you to verify user identities without revealing sensitive data, ensuring privacy and security in your application.
6 changes: 3 additions & 3 deletions docs/zk-passport/guide-proof-of-citizenship.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ You can check out this flow in the sandbox: <OutLink href="https://app.rarime.co
## Pre-requisites

:::tip
You can use this public instance of `verifier-svc` for testing: <OutLink href="https://api.app.rarime.com/">https://api.app.rarime.com/</OutLink>
You can use this public instance of `verificator-svc` for testing: <OutLink href="https://api.app.rarime.com/">https://api.app.rarime.com/</OutLink>
:::

To get started, you SHOULD deploy your own instance of https://github.com/rarimo/verificator-svc. This service encapsulates proof verification and provides a convenient REST API for requesting parameters for the QR code, checking the user verification status, etc. You need to trust the instance of `verifier-svc` so the best option is to host your own instance.
To get started, you SHOULD deploy your own instance of https://github.com/rarimo/verificator-svc. This service encapsulates proof verification and provides a convenient REST API for requesting parameters for the QR code, checking the user verification status, etc. You need to trust the instance of `verificator-svc` so the best option is to host your own instance.

API docs: <OutLink href="https://rarimo.github.io/verificator-svc/">verificator-svc | ReDoc</OutLink>

Expand All @@ -42,7 +42,7 @@ Links for installation:

## Step #2: Render a QR code with a verification request in your app

To request data for the QR code, you need to call this endpoint on the `verifier-svc`:
To request data for the QR code, you need to call this endpoint on the `verificator-svc`:
<OutLink href="https://api.stage.rarime.com/integrations/verificator-svc/private/verification-link">https://api.stage.rarime.com/integrations/verificator-svc/private/verification-link</OutLink>

The following JS snippet gets data for a QR code for a passport verification with a uniqueness check on:
Expand Down
54 changes: 54 additions & 0 deletions docs/zk-passport/guide-setting-up-cross-chain-replication.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
description: Set up ZK Passport Registry replication to verify ZK Passport proofs on any EVM-compatible chain.
sidebar_label: "Guide: setting up cross-chain replication"
---

import OutLink from "@site/src/components/OutLink";
import IdealImage from '@site/src/components/IdealImage';

# Guide: Setting up cross-chain replication for ZK Passport

:::info
Native state transfer to Ethereum L1 is currently under construction.
:::

This guide walks you through the process of setting up cross-chain replication for ZK Passport Registry state. By the end of this tutorial, you will have:

1. Deployed the **RegistrationSMTReplicator** contract on the target chain.
1. Set up your relayer or front-end submission flow.

## Step 1: Deploy the RegistrationSMTReplicator

The **RegistrationSMTReplicator** handles the replication of state from the ZK Registry onto your chain. This ensures your chain is kept up to date with changes to passport registrations.

1. **Obtain the contract code** for `RegistrationSMTReplicator` (contact the provider of the ZK Registry or check their repository for the contract source).

1. **Deploy** the `RegistrationSMTReplicator` to your chain:

```solidity
// Example snippet (pseudo-code)
RegistrationSMTReplicator replicator = new RegistrationSMTReplicator(
registryRoot,
allowedUpdaterAddress
);
```

## Step 2: Set up the relayer or front-end submission flow to replicate the states

To keep the state of the ZK Registry in sync with your chain, you need to set up a relayer or front-end submission flow. This will ensure that any changes in the ZK Registry are reflected in the `RegistrationSMTReplicator` contract.

You have two options:
1. **Option A**: Set up a relayer service that listens for events from the ZK Registry and submits state updates to your `RegistrationSMTReplicator` instance.

- This relayer will listen for events such as new passport registrations or updates to existing registrations.
- When an event is detected, the relayer will call the `updateState(...)` function on the `RegistrationSMTReplicator` contract.
- This option is more user-friendly but requires you to pay the gas for the state updates on your chain.

1. **Option B**: Send the updates the state update transactions on-demand from your front-end:
- This option is more cost-effective but requires the user to pay the gas for the state updates on your chain.
- You can use the `updateState(...)` function on the `RegistrationSMTReplicator` contract to submit state updates.


To set up a relayer for the **Option A**, follow the instructions in <OutLink href="https://github.com/rarimo/proof-verification-relayer">proof-verification-relayer README</OutLink>.

The **Option B** is more more complex to set up, so we recommended reaching out to Rarimo contributors for help.
93 changes: 93 additions & 0 deletions docs/zk-passport/guide-setting-up-verificator-svc.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
---
description: Learn how to set up the verificator-svc service for ZK Passport.
sidebar_label: "Guide: hosting your own off-chain verificator"
---
import OutLink from "@site/src/components/OutLink";
import IdealImage from '@site/src/components/IdealImage';

# Guide: Setting up your own off-chain verificator for ZK Passport

`verificator-svc` is a service that verifies ZK Passport proofs off-chain. It provides a convenient REST API for requesting parameters for the QR code, checking the user verification status, etc. You need to trust the instance of `verificator-svc`, so the best option is to host your own instance.

## Prerequisites

- Docker
- PostgreSQL 10+

## Step 1: Create a config fields

Here is a sample config file for `verificator-svc`. Set the appropriate `db` connection string, `verifier.event_id`, and `callback.url` values for your deployment:

```yaml title="config.yaml"
log:
level: debug
disable_sentry: true

db:
# Your PostgreSQL connection string goes here
url: "postgres://..."

verifier:
# Pick an arbitrary sting as a default value for the event_id.
event_id: "my_app_event_id"
verification_key_path: "./proof_keys/passport.json"
allowed_identity_timestamp: 1741972260
multiproof: false
preserve_user_id_case: false
erc_1155: "0x0000000000000000000000000000000000000000"

callback:
# URL of the current instance of verifier-svc
url: "http://mybackend.net:8000"

listener:
addr: :8000

cop:
disabled: true
endpoint: "http://..."
upstream: "http://..."
service_name: verificator-svc
service_port: 80



signature_verification:
pub_key: "04e29323ad356ab524fa5dbe3e490244e741b4d445ac7d2ee5f321556b3fda616bb9d2f2216fc27e099ab3019103cca872679e130629b2b90ea16cedb2b2136371"

poseidonsmt_root_verifier:
rpc: "https://l2.rarimo.com"
contract: "0x479F84502Db545FA8d2275372E0582425204A879"
request_timeout: 10s

auth:
enabled: false
addr: http://rarime-auth
```

{
// TODO: explain other params e.g. `erc_1155`, `signature_verification`
}


## Step 2: Run the service

Run the service in docker with the following command:

```bash
docker build -t github.com/rarimo/verificator-svc .
docker run -e KV_VIPER_FILE=/config.yaml github.com/rarimo/verificator-svc
```


{
// TODO: add sample output
}

## API reference

`verificator-svc` API reference can be found here: <OutLink href="https://rarimo.github.io/verificator-svc/">https://rarimo.github.io/verificator-svc/</OutLink>

## Running from source and contributing

Refer to the <OutLink href="https://github.com/rarimo/verificator-svc">README</OutLink> on github.
Loading