### Install @rarimo/zk-passport-react with Yarn Source: https://docs.rarimo.com/zk-passport/guide-off-chain-verification Install the React package for off-chain verification using Yarn. ```bash yarn add @rarimo/zk-passport-react ``` -------------------------------- ### Install @rarimo/zk-passport-react with Bun Source: https://docs.rarimo.com/zk-passport/guide-off-chain-verification Install the React package for off-chain verification using Bun. ```bash bun add @rarimo/zk-passport-react ``` -------------------------------- ### Install @rarimo/passport-contracts with Bun Source: https://docs.rarimo.com/zk-passport/guide-setting-up-cross-chain-replication Install the Rarimo Passport Contracts package using Bun. ```bash bun add @rarimo/passport-contracts ``` -------------------------------- ### Install @rarimo/zk-passport-react with pnpm Source: https://docs.rarimo.com/zk-passport/guide-off-chain-verification Install the React package for off-chain verification using pnpm. ```bash pnpm add @rarimo/zk-passport-react ``` -------------------------------- ### Install @rarimo/passport-contracts with Yarn Source: https://docs.rarimo.com/zk-passport/guide-setting-up-cross-chain-replication Install the Rarimo Passport Contracts package using Yarn. ```bash yarn add @rarimo/passport-contracts ``` -------------------------------- ### Install @rarimo/passport-contracts with npm Source: https://docs.rarimo.com/zk-passport/guide-setting-up-cross-chain-replication Install the Rarimo Passport Contracts package using npm. ```bash npm install @rarimo/passport-contracts ``` -------------------------------- ### Install @rarimo/passport-contracts with pnpm Source: https://docs.rarimo.com/zk-passport/guide-setting-up-cross-chain-replication Install the Rarimo Passport Contracts package using pnpm. ```bash pnpm add @rarimo/passport-contracts ``` -------------------------------- ### Install @rarimo/zk-passport-react with npm Source: https://docs.rarimo.com/zk-passport/guide-off-chain-verification Install the React package for off-chain verification using npm. Run in your project directory. ```bash npm install @rarimo/zk-passport-react ``` -------------------------------- ### Install @rarimo/zk-passport with Bun Source: https://docs.rarimo.com/zk-passport/guide-off-chain-verification Install the low-level package for non-React applications using Bun. ```bash bun add @rarimo/zk-passport ``` -------------------------------- ### Install @rarimo/zk-passport with pnpm Source: https://docs.rarimo.com/zk-passport/guide-off-chain-verification Install the low-level package for non-React applications using pnpm. ```bash pnpm add @rarimo/zk-passport ``` -------------------------------- ### Install @rarimo/zk-passport with npm Source: https://docs.rarimo.com/zk-passport/guide-off-chain-verification Install the low-level package for non-React applications using npm. ```bash npm install @rarimo/zk-passport ``` -------------------------------- ### Install @rarimo/zk-passport with Yarn Source: https://docs.rarimo.com/zk-passport/guide-off-chain-verification Install the low-level package for non-React applications using Yarn. ```bash yarn add @rarimo/zk-passport ``` -------------------------------- ### Install ZK Passport React and viem Source: https://docs.rarimo.com/zk-passport/guide-on-chain-verification Install the ZK Passport React SDK and the viem library in your React project. Requires viem version 2.31.0 or later. ```bash npm install viem@^2.31.0 @rarimo/zk-passport-react ``` -------------------------------- ### Install @rarimo/passport-contracts with npm, Yarn, pnpm, or Bun Source: https://docs.rarimo.com/zk-passport/guide-on-chain-verification Install the @rarimo/passport-contracts npm package using your preferred package manager. The package provides the contracts needed for on-chain ZK Passport verification. ```bash npm install @rarimo/passport-contracts ``` ```bash yarn add @rarimo/passport-contracts ``` ```bash pnpm add @rarimo/passport-contracts ``` ```bash bun add @rarimo/passport-contracts ``` -------------------------------- ### Clone the Bionetta repository Source: https://docs.rarimo.com/zkml-bionetta/tutorial-creating-a-zkml-model Use this command to clone the repository containing the Bionetta framework and the MNIST example model. ```bash git clone git@github.com:rarimo/bionetta.git ``` -------------------------------- ### Parse MNIST Dataset Source: https://docs.rarimo.com/zkml-bionetta/tutorial-creating-a-zkml-model Example code for loading and preprocessing the MNIST dataset for neural network training. ```python (X_train, y_train), (X_test, y_test) = tf.keras.datasets.mnist.load_data() X_train = X_train / 255.0 X_test = X_test / 255.0 X_train = np.expand_dims(X_train, axis=-1) # Add channel dimension X_test = np.expand_dims(X_test, axis=-1) # Add channel dimension y_train = tf.keras.utils.to_categorical(y_train, 10) y_test = tf.keras.utils.to_categorical(y_test, 10) ``` -------------------------------- ### Get signed root state from relayer API Source: https://docs.rarimo.com/zk-passport/guide-setting-up-cross-chain-replication Fetches the signed state for a given root from the proof-verification-relayer API. Returns the signature and timestamp needed for submitting state updates. ```typescript async function getSignedRootState(root: string) { const API_BASE_URL = 'https://api.example.com' const requestUrl = new URL(`${API_BASE_URL}/integrations/proof-verification-relayer/v2/state`) requestUrl.searchParams.set('filter[root]', root) const res = await fetch(requestUrl.toString()) const { data } = await res.json() return { // Signature of root state signed by relayer private key. signature: data.attributes.signature, // Time when the event was caught, a.k.a state transition timestamp timestamp: data.attributes.timestamp, } } ``` -------------------------------- ### Sample config.yaml for verificator-svc Source: https://docs.rarimo.com/zk-passport/guide-setting-up-verificator-svc Sample configuration file for verificator-svc. Set the db connection string, verifier.event_id, and callback.url values for your deployment. The file includes settings for logging, verification, callback, listener, cop, signature verification, poseidonsmt root verifier, and auth. ```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 ``` -------------------------------- ### Configure Training and Save Weights Source: https://docs.rarimo.com/zkml-bionetta/tutorial-creating-a-zkml-model Set training hyperparameters, define callbacks, save circuit weights, and execute the model training process. ```python hyperparams = tfb.hyperparameters.TrainingHyperparameters({ 'epochs': 1, 'validation_split': 0.9 }) DEBUG_BATCH_SIZE = 4 random_idx = np.random.randint(len(X_train), size=DEBUG_BATCH_SIZE) X_debug = X_train[random_idx] y_debug = y_train[random_idx] callbacks = [ tfb.callbacks.BionettaSubmodelCheckpoint( model, "./examples/bionetta_mnist_test_model/training" ), tfb.callbacks.ExamplePredictionsCallback(X_debug, y_debug), ] model.save_circuit_weights('./bionetta-mnist-temp', compress=False) model.compile(loss='mse', optimizer='adam') model.fit(X_train, y_train, epochs=hyperparams.epochs, validation_data=(X_test, y_test), validation_split=hyperparams.validation_split, callbacks=callbacks) ``` -------------------------------- ### Execute Training Script Source: https://docs.rarimo.com/zkml-bionetta/tutorial-creating-a-zkml-model Run the training script using the Python module execution command. ```bash python3 -m examples.bionetta_mnist ``` -------------------------------- ### ExampleVerifier interface with verifyProof Source: https://docs.rarimo.com/zk-passport/contracts Defines the common interface for all generated verifier contracts. Each verifier accepts a ZK proof and public signals, returning a boolean indicating validity. The actual proof verification logic is omitted and replaced with a placeholder. ```solidity contract ExampleVerifier { /* some constants */ function verifyProof( uint[2] calldata _pA, uint[2][2] calldata _pB, uint[2] calldata _pC, uint[4] calldata _pubSignals ) public view returns (bool) { /* ... */ } } ``` -------------------------------- ### Build and run verificator-svc with Docker Source: https://docs.rarimo.com/zk-passport/guide-setting-up-verificator-svc Commands to build and run the verificator-svc service in Docker. The run command sets the KV_VIPER_FILE environment variable to point to the config file. ```bash docker build -t github.com/rarimo/verificator-svc . docker run -e KV_VIPER_FILE=/config.yaml github.com/rarimo/verificator-svc ``` -------------------------------- ### Fetch verified attribute data from verificator-svc Source: https://docs.rarimo.com/zk-passport/guide-off-chain-verification Fetches verified attribute data for a user after their status is 'verified'. The example retrieves the nationality attribute as an ISO 3166 alpha-3 country code (e.g., 'UKR'), with a note that German passports may return a single-letter 'D'. Other attributes depend on the verification options requested. ```javascript const response = await fetch(`${backendUrl}/integrations/verificator-svc/private/user/${userId}`) const { data } = await response.json() // Depending on what attributes you requested in your verification options // For example, if you requested nationalityCheck: // ISO 3166 alpha-3 country code: https://www.iban.com/country-codes // Note: German passports may have a single-letter "D" code const citizenshipISOCode = data.attributes.nationality // e.g. "UKR" // Other attributes might be available depending on your verification request ``` -------------------------------- ### Prove and verify in Python Source: https://docs.rarimo.com/zkml-bionetta/tutorial-creating-a-zkml-model Generate and verify proofs directly within a Python script using Bionetta's model methods. ```python proof_dir = './examples/simple_mnist_circuits/proof' model.prove( input=test_input, target_dir=proof_dir ) model.verify(proof_dir=proof_dir) ``` -------------------------------- ### Generate Groth16 proof with snarkjs Source: https://docs.rarimo.com/zkml-bionetta/tutorial-creating-a-zkml-model Use the snarkjs CLI to generate a proof for the neural network inference using the circuit's zkey and witness files. ```bash snarkjs groth16 prove \ examples/bionetta_mnist_circuits/sequential_circom/sequential.zkey \ examples/bionetta_mnist_circuits/sequential_circom/sequential.wtns \ proof.json public.json ``` -------------------------------- ### Deploy and initialize RegistrationSMTReplicator Source: https://docs.rarimo.com/zk-passport/guide-setting-up-cross-chain-replication Deploys the RegistrationSMTReplicator contract and initializes it with the relayer oracle address and the source SMT address of the original ZK Passport Registry on Rarimo L2. ```typescript import { RegistrationSMTReplicator } from '@rarimo/passport-contracts'; const replicator = await RegistrationSMTReplicator.deploy({ // Specify the chain and network parameters here }); const oracle = '0x...'; // Replace with your relayer address from the previous step const sourceSMT = '0x479F84502Db545FA8d2275372E0582425204A879'; // This is the address of the original ZK Passport Registry on Rarimo L2. await replicator.__RegistrationSMTReplicator_init( [oracle], // list of oracle public keys that can submit roots directly sourceSMT // contract address of the original registry on Rarimo L2 ); ``` -------------------------------- ### Compile ZKML Circuits Source: https://docs.rarimo.com/zkml-bionetta/tutorial-creating-a-zkml-model Compile the model circuits using a test input and the specified powers of tau file. ```python test_input = X_test[np.random.randint(len(X_test))] model.compile_circuits( path='./examples/bionetta_mnist_circuits', test_input=test_input, powers_of_tau_path='./examples/powersOfTau_20.ptau' ) ``` -------------------------------- ### Import TD3QueryProofVerifier contract Source: https://docs.rarimo.com/zk-passport/guide-on-chain-verification Import the TD3QueryProofVerifier contract from the Rarimo Passport Contracts library. This contract is responsible for verifying ZK proofs on-chain and often comes with a precompiled ZK circuit. ```solidity import {TD3QueryProofVerifier } from "@rarimo/passport-contracts/sdk/verifier/TD3QueryProofVerifier.sol"; ``` -------------------------------- ### Integrate proof verification into a smart contract with AQueryProofExecutor Source: https://docs.rarimo.com/zk-passport/guide-on-chain-verification Skeleton contract that integrates ZK Passport proof verification by extending AQueryProofExecutor. Override _beforeVerify to check nullifier reuse, _afterVerify to perform actions like minting or granting roles, and _buildPublicSignals to construct the public signals for verification. ```solidity pragma solidity ^0.8.28; import {IPoseidonSMT} from "@rarimo/passport-contracts/interfaces/state/IPoseidonSMT.sol"; import {AQueryProofExecutor} from "@rarimo/passport-contracts/sdk/AQueryProofExecutor.sol"; import {PublicSignalsBuilder} from "@rarimo/passport-contracts/sdk/lib/PublicSignalsBuilder.sol"; contract MyPassportContract is AQueryProofExecutor { struct UserData { uint256 nullifier; uint256 identityCreationTimestamp; } mapping(uint256 => bool) public usedNullifiers; constructor(address registrationSMT_, address verifier_) { __AQueryProofExecutor_init(registrationSMT_, verifier_); } // Called before proof verification function _beforeVerify(bytes32, uint256, bytes memory userPayload_) public override { (address user, UserData memory userData) = abi.decode( userPayload_, (address, UserData) ); require(!usedNullifiers[userData.nullifier], "Nullifier already used"); usedNullifiers[userData.nullifier] = true; } // Called after successful proof verification function _afterVerify(bytes32, uint256, bytes memory userPayload_) public override { (address user, UserData memory userData) = abi.decode( userPayload_, (address, UserData) ); // Grant access, mint tokens, or perform other actions // Example: grantAccess(user); } // Builds the public signals for verification function _buildPublicSignals( bytes32, uint256 currentDate_, bytes memory userPayload_ ) public override returns (uint256 dataPointer_) { (address user, UserData memory userData) = abi.decode( userPayload_, (address, UserData) ); // Query proof verification logic here return dataPointer_; } } ``` -------------------------------- ### ProposalsState.sol Interface Source: https://docs.rarimo.com/freedom-tool/smart-contracts-reference Solidity interface for the ProposalsState contract, showing the contract declaration, state variables, structs, enum, and function signatures. The contract inherits OwnableUpgradeable, AccessControlUpgradeable, and UUPSUpgradeable. Functions include createProposal, addFundsToProposal, changeProposalDuration, hideProposal, getProposalEventId, and getProposalInfo. ```Solidity contract ProposalsState is OwnableUpgradeable, AccessControlUpgradeable, UUPSUpgradeable { uint256 public lastProposalId; uint256 public minFundingAmount; struct ProposalConfig { uint64 startTimestamp; uint64 duration; uint256 multichoice; uint256[] acceptedOptions; string description; address[] votingWhitelist; // must be sorted bytes[] votingWhitelistData; // data per voting whitelist } enum ProposalStatus { None, Waiting, Started, Ended, DoNotShow } struct ProposalInfo { address proposalSMT; ProposalStatus status; ProposalConfig config; uint256[MAXIMUM_CHOICES_PER_OPTION][] votingResults; } function createProposal( ProposalConfig calldata proposalConfig_ ) external payable { // ... } function addFundsToProposal( uint256 proposalId_ ) external payable { // ... } function changeProposalDuration( uint256 proposalId_, uint64 newDuration_ ) external onlyProposalCreator(proposalId_) { // ... } function hideProposal( uint256 proposalId_ ) external onlyProposalCreator(proposalId_) { // ... } function getProposalEventId( uint256 proposalId_ ) external view returns (uint256) { // ... } function getProposalInfo( uint256 proposalId_ ) external view returns (ProposalInfo memory info_) { // ... } } ``` -------------------------------- ### Verify Groth16 proof with snarkjs Source: https://docs.rarimo.com/zkml-bionetta/tutorial-creating-a-zkml-model Verify the generated proof against the public inputs and the verification key. ```bash snarkjs groth16 verify \ examples/bionetta_mnist_circuits/sequential_circom/verification_key.json \ public.json proof.json ``` -------------------------------- ### Expected verification output Source: https://docs.rarimo.com/zkml-bionetta/tutorial-creating-a-zkml-model The console output indicating a successful verification of the proof. ```text [INFO] snarkJS: OK! ``` -------------------------------- ### Registration2 Contract Interface Source: https://docs.rarimo.com/zk-passport/contracts The full interface of the Registration2 contract, showing state variables and all external functions for certificate and passport management. Includes placeholders for ZKP verification logic. ```solidity contract Registration2 is Initializable, TSSUpgradeable { StateKeeper public stateKeeper; mapping(bytes32 => address) public certificateDispatchers; mapping(bytes32 => address) public passportDispatchers; mapping(bytes32 => address) public passportVerifiers; function registerCertificate( Certificate memory certificate_, ICAOMember memory icaoMember_, bytes32[] memory icaoMerkleProof_ ) external virtual { /* ... */ } function revokeCertificate(bytes32 certificateKey_) external virtual { stateKeeper.removeCertificate(certificateKey_); } function register( bytes32 certificatesRoot_, uint256 identityKey_, uint256 dgCommit_, Passport memory passport_, VerifierHelper.ProofPoints memory zkPoints_ ) external virtual { /* ... */ } function registerViaNoir( bytes32 certificatesRoot_, uint256 identityKey_, uint256 dgCommit_, Passport memory passport_, bytes memory zkPoints_ ) external virtual { /* ... */ } function revoke(uint256 identityKey_, Passport memory passport_) external virtual { /* ... */ } function reissueIdentity( bytes32 certificatesRoot_, uint256 identityKey_, uint256 dgCommit_, Passport memory passport_, VerifierHelper.ProofPoints memory zkPoints_ ) external virtual { /* ... */ } function reissueIdentityViaNoir( bytes32 certificatesRoot_, uint256 identityKey_, uint256 dgCommit_, Passport memory passport_, bytes memory zkPoints_ ) external virtual { /* ... */ } function updateDependency( MethodId methodId_, bytes calldata data_, bytes calldata proof_ ) external virtual { /* ... */ } } ``` -------------------------------- ### RegistrationSMTReplicator Interface Source: https://docs.rarimo.com/zk-passport/contracts Interface for the RegistrationSMTReplicator contract, which replicates the Registration SMT root on target chains when the canonical StateKeeper is unavailable. Root updates can be pushed by authorized oracles via transitionRoot or by anyone with an oracle-signed message via transitionRootWithSignature, using the ECDSA-recovered message keccak256(abi.encodePacked(REGISTRATION_ROOT_PREFIX, sourceSMT, address(this), newRoot, timestamp)). isRootValid returns true if the root is the latest or observed within ROOT_VALIDITY (1 hour). Owners manage the oracle set and can update sourceSMT; the contract follows UUPS upgradeability and multi-owner controls. ```solidity contract RegistrationSMTReplicator is IPoseidonSMT { uint256 public constant ROOT_VALIDITY = 1 hours; string public constant REGISTRATION_ROOT_PREFIX = "Rarimo root"; address public sourceSMT; bytes32 public latestRoot; uint256 public latestTimestamp; event RootTransitioned(bytes32 newRoot, uint256 transitionTimestamp); function __RegistrationSMTReplicator_init( address[] memory oracles_, address sourceSMT_ ) external; function addOracles(address[] memory oracles_) external; function removeOracles(address[] memory oracles_) external; function setSourceSMT(address newSourceSMT_) external; function transitionRoot(bytes32 newRoot_, uint256 transitionTimestamp_) external; function transitionRootWithSignature( bytes32 newRoot_, uint256 transitionTimestamp_, bytes memory signature_ ) external; function isRootValid(bytes32 root_) external view returns (bool); function isRootLatest(bytes32 root_) public view returns (bool); function isOracle(address oracle_) public view returns (bool); function getOracles() external view returns (address[] memory); } ``` -------------------------------- ### TD3QueryProofVerifier Interface Source: https://docs.rarimo.com/zk-passport/contracts Interface for the TD3QueryProofVerifier contract. The verifyProof function verifies TD3-query zero-knowledge proofs produced by the Query circuit (e.g., age, uniqueness, country masks) without revealing raw passport data. It accepts Groth16 proof points and the public signals array (23 items for Query circuit) and returns true if valid. Intended for SDK-level integrations where on-chain verification of query proofs is needed. ```solidity contract TD3QueryProofVerifier { function verifyProof( uint256[2] calldata _pA, uint256[2][2] calldata _pB, uint256[2] calldata _pC, uint256[] calldata _pubSignals ) external view returns (bool) { /* ... */ } } ``` -------------------------------- ### Generate a relayer key pair with ethers Source: https://docs.rarimo.com/zk-passport/guide-setting-up-cross-chain-replication Generates a random wallet using ethers and prints the address and private key. The private key must be securely stored for the relayer to sign state updates. ```typescript import { ethers } from 'ethers'; const wallet = ethers.Wallet.createRandom(); console.log('Address:', wallet.address); console.log('Private Key:', wallet.privateKey); ``` -------------------------------- ### PublicSignalsBuilder library interface Source: https://docs.rarimo.com/zk-passport/contracts Defines the PublicSignalsBuilder library interface for constructing Query circuit public signals in the exact index layout expected by verifiers. Use it to build public signal arrays with methods like withName, withIdStateRoot, and withCurrentDate. withIdStateRoot validates the root via IPoseidonSMT(registrationSMT).isRootValid before writing at index 11, and withCurrentDate parses yyMMdd to a timestamp enforcing a ±timeBound window using Date2Time utilities. The library produces either uint256[] or bytes32[] views of the same in-memory array for downstream verifier calls. ```solidity library PublicSignalsBuilder { uint256 public constant PROOF_SIGNALS_COUNT = 23; function newPublicSignalsBuilder( uint256 selector_, uint256 nullifier_ ) internal pure returns (uint256 dataPointer_); function withName(uint256 dataPointer_, uint256 name_) internal pure; function withNameResidual(uint256 dataPointer_, uint256 nameResidual_) internal pure; function withNationality(uint256 dataPointer_, uint256 nationality_) internal pure; function withCitizenship(uint256 dataPointer_, uint256 citizenship_) internal pure; function withSex(uint256 dataPointer_, uint256 sex_) internal pure; function withEventIdAndData(uint256 dataPointer_, uint256 eventId_, uint256 eventData_) internal pure; function withIdStateRoot(uint256 dataPointer_, bytes32 idStateRoot_) internal view; function withSelector(uint256 dataPointer_, uint256 selector_) internal pure; function withCurrentDate(uint256 dataPointer_, uint256 currentDate_, uint256 timeBound_) internal view; function withTimestampLowerboundAndUpperbound(uint256 dataPointer_, uint256 lb_, uint256 ub_) internal pure; function withIdentityCounterLowerbound(uint256 dataPointer_, uint256 lb_, uint256 ub_) internal pure; function withBirthDateLowerboundAndUpperbound(uint256 dataPointer_, uint256 lb_, uint256 ub_) internal pure; function withExpirationDateLowerboundAndUpperbound(uint256 dataPointer_, uint256 lb_, uint256 ub_) internal pure; function withCitizenshipMask(uint256 dataPointer_, uint256 citizenshipMask_) internal pure; function buildAsUintArray(uint256 dataPointer_) internal pure returns (uint256[] memory); function buildAsBytesArray(uint256 dataPointer_) internal pure returns (bytes32[] memory); } ``` -------------------------------- ### RegistrationSMTReplicator Interface Source: https://docs.rarimo.com/freedom-tool/smart-contracts-reference The interface for the RegistrationSMTReplicator contract, defining the root transition and validation logic. ```solidity contract RegistrationSMTReplicator is MultiOwnable, UUPSUpgradeable { uint256 public constant ROOT_VALIDITY = 1 hours; bytes32 public latestRoot; uint256 public latestTimestamp; function transitionRoot( bytes32 newRoot_, uint256 transitionTimestamp_, bytes calldata proof_ ) external virtual onlyOwner { // ... } function isRootValid(bytes32 root_) external view virtual returns (bool) { // ... } function isRootLatest(bytes32 root_) public view virtual returns (bool) { // ... } } ```