Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
LABS
Guides

Setting Up a Privacy-First Transaction Framework

A technical guide for developers implementing privacy-enhancing technologies like zk-SNARKs and stealth addresses. Covers trade-offs, integration patterns, and code examples.
Chainscore © 2026
introduction
PRACTICAL GUIDE

Setting Up a Privacy-First Transaction Framework

This guide explains how to implement a privacy-first framework for on-chain transactions, covering core concepts like zero-knowledge proofs, stealth addresses, and practical integration steps.

On-chain privacy frameworks allow users to transact on public blockchains without exposing sensitive financial data like wallet balances, transaction amounts, or counterparty relationships. Unlike traditional financial systems, most blockchains like Ethereum and Bitcoin broadcast all transaction details publicly. Privacy frameworks address this by using cryptographic primitives such as zero-knowledge proofs (ZKPs) and stealth address protocols. These technologies enable the validation of transactions while keeping the core data confidential, moving beyond simple mixer services to provide programmable privacy at the protocol level.

The core component of a modern privacy framework is the commitment scheme. When a user initiates a private transaction, they generate a cryptographic commitment (like a Pedersen commitment) to the transaction amount and a nullifier. This commitment is published on-chain, but the actual value is hidden. To spend these committed funds later, the user must provide a zero-knowledge proof, such as a zk-SNARK, that proves: 1) the commitment is valid, 2) the user owns the funds, and 3) the new outputs do not create or destroy value (conservation of assets). Popular implementations include zk.money (based on Aztec) and Tornado Cash, which use this model.

For developers, integrating privacy starts with choosing a framework. For Ethereum, the Aztec Connect SDK allows smart contracts to leverage private transactions via a rollup. A basic flow involves depositing funds into a privacy pool, generating proofs off-chain with tools like snarkjs, and submitting the proof for on-chain verification. Here's a conceptual snippet for initiating a private transfer using a circuit:

javascript
// Pseudocode for generating a private transaction proof
const { proof, publicSignals } = await snarkjs.groth16.fullProve(
  { amount: secretAmount, secret: nullifierSecret },
  "circuit.wasm",
  "proving_key.zkey"
);
// Submit proof and public signals to the verifier contract
await verifierContract.verifyProof(proof, publicSignals);

This proof convinces the network the transaction is valid without revealing the secretAmount.

Stealth addresses are another critical pillar, solving the recipient privacy problem. Instead of reusing a public address, a sender generates a one-time stealth address for the recipient using their public viewing key. Protocols like Zcash's Sapling or Monero use this by default. On Ethereum, standards like ERC-5564 (Stealth Addresses) are emerging. This ensures that even if Alice sends multiple transactions to Bob, on-chain observers cannot link them to Bob's primary address or to each other, breaking the heuristic analysis used by blockchain surveillance firms.

When designing a system, key management is paramount. Users must safeguard a spending key (to authorize transactions) and a viewing key (to decrypt transaction details). Losing the spending key means losing funds irrevocably, as there is no centralized recovery. Frameworks must also consider regulatory compliance. Selective disclosure features, enabled by zero-knowledge proofs, allow users to reveal specific transaction details to auditors or tax authorities without exposing their entire financial history, balancing privacy with necessary oversight.

The future of on-chain privacy is moving towards privacy-preserving smart contracts and cross-chain private bridges. Projects like Aleo and Aztec are building zk-rollups that keep contract logic and state private. The main challenges remain user experience—managing keys and proof generation—and cost, as generating ZKPs is computationally intensive. However, with hardware acceleration and recursive proofs, these barriers are lowering, paving the way for private DeFi and identity systems that protect user data by default.

prerequisites
PREREQUISITES AND SETUP

Setting Up a Privacy-First Transaction Framework

This guide outlines the essential tools and foundational knowledge required to build and interact with privacy-preserving protocols on Ethereum and other EVM chains.

Before writing any code, you need a secure development environment. Start by installing Node.js (v18 or later) and a package manager like npm or yarn. You'll also need a code editor such as VS Code. The core tool for interacting with blockchains is an Ethereum client library. For JavaScript/TypeScript projects, viem and ethers.js are the modern standards. Install them via npm install viem or npm install ethers. These libraries handle wallet creation, transaction signing, and contract interaction without exposing private keys to your application's frontend.

A critical prerequisite is understanding how to manage private keys securely. Never hardcode them. For development, use environment variables with a .env file (add it to your .gitignore). Tools like dotenv can load these variables. For transaction signing, you'll use a Wallet or Account object. In viem, you create a private key account with createWalletClient and privateKeyToAccount. In a production context, consider using Hardware Wallets or Signer SaaS solutions like Privy or Dynamic to delegate key management and enhance user security.

You will need access to a blockchain node to broadcast transactions. For testing, you can use a Local Development Chain like Anvil (from Foundry) or Hardhat Network. For interacting with live testnets (e.g., Sepolia) or mainnets, you need a Node Provider. Options include public RPC endpoints (limited), dedicated services like Alchemy or Infura, or running your own node. Configure your provider in your client; for example, in viem: createPublicClient({ transport: http('https://eth-sepolia.g.alchemy.com/v2/YOUR_KEY') }).

Privacy-focused transactions often rely on zero-knowledge proofs or stealth address systems. To work with these, you may need additional tooling. For zk-SNARKs, familiarize yourself with Circom for circuit design and snarkjs for proof generation. For projects like Tornado Cash or zk.money, you'll need to interact with their specific smart contracts and often use a relayer service to submit transactions anonymously. Understanding the basic flow—generating a proof off-chain and submitting it with a transaction—is essential.

Finally, ensure you have test ETH or the native token for your target chain. Use a faucet for testnets (e.g., Sepolia Faucet from Alchemy). For mainnet simulations, always start on a testnet. Your setup is complete when you can: 1) Create a wallet client, 2) Connect to a provider, 3) Read blockchain state (e.g., get a balance), and 4) Sign a message. This foundation is necessary before implementing advanced privacy features like confidential transfers or identity shielding.

key-concepts-text
CORE PRIVACY TECHNOLOGIES EXPLAINED

Setting Up a Privacy-First Transaction Framework

A technical guide to implementing privacy-enhancing technologies for secure and confidential on-chain transactions.

A privacy-first transaction framework is a system designed to protect user data on public blockchains. Unlike transparent ledgers like Bitcoin or Ethereum's base layer, these frameworks use cryptographic techniques to obscure transaction details—such as sender, recipient, and amount—while maintaining network consensus. The primary goal is to achieve financial confidentiality without sacrificing security or decentralization. This is critical for enterprise adoption, personal financial privacy, and fungibility of digital assets. Core technologies enabling this include zero-knowledge proofs, stealth addresses, and confidential transactions.

Zero-Knowledge Proofs (ZKPs) are the cornerstone of modern on-chain privacy. Protocols like Zcash (using zk-SNARKs) and Aztec (using PLONK) allow a prover to verify a statement's truth without revealing the underlying data. For example, a ZKP can prove you have sufficient funds for a payment without disclosing your balance. Setting this up involves using a client library like snarkjs to generate and verify proofs. A basic flow includes creating a circuit, a trusted setup (for some systems), generating a proof from private inputs, and submitting it to a verifier contract.

Stealth Addresses and Confidential Transactions complement ZKPs. A stealth address system, used by Monero and proposed in ERC-5564, generates a one-time receiving address for each transaction, breaking the link on-chain. Confidential Transactions, as implemented in Elements Sidechains, encrypt transaction amounts using Pedersen Commitments, so only participants can decrypt them. Implementing these often requires integrating specific wallet SDKs or smart contract libraries that handle the key derivation and encryption processes automatically for users.

For developers, building a privacy layer starts with choosing a stack. For Ethereum, you might use the Aztec Noir language to write private smart contracts or Tornado Cash's circuit logic (conceptually) for mixing. A practical step is to use a ZK rollup like zkSync or Scroll with native privacy features, or a dedicated privacy L2 like Aleo. The setup involves configuring a prover service, deploying verifier contracts, and ensuring your application's frontend can generate ZK proofs in-browser using tools like WebAssembly-based proving engines.

Key considerations for a production framework include trust assumptions, computational overhead, and regulatory compliance. Some ZKP systems require a trusted setup ceremony, introducing a potential weakness. Proof generation is also computationally intensive, requiring optimized circuits and potentially offloading to servers. Furthermore, privacy protocols must implement compliance tools like view keys or auditability features to allow selective disclosure for legal purposes, balancing privacy with necessary transparency.

The future of private transactions is moving towards universal privacy layers and ZK co-processors. Projects like Polygon Miden and Espresso Systems are working to make ZK proofs a seamless part of any transaction. The ultimate goal is a framework where privacy is the default, not an add-on, built with standardized primitives that developers can integrate as easily as they do with today's wallet connection libraries.

TRUST SETUP & PROTOCOLS

Privacy Technology Comparison

A technical comparison of leading privacy-enhancing protocols for blockchain transactions, focusing on cryptographic assumptions and practical constraints.

Feature / MetricTornado CashAztec ProtocolZcash (Sapling)

Cryptographic Base

zk-SNARKs

zk-SNARKs (Plonk)

zk-SNARKs (Groth16)

Trusted Setup Required

Transaction Privacy

Sender, Receiver, Amount

Full Transaction (Private DeFi)

Sender, Receiver, Amount

Smart Contract Compatibility

Ethereum Only

EVM & Custom Aztec VM

Limited (Zcash Chain)

Typical Relayer Fee

$10-50

$5-20

Miner Fee Only

Proving Time (avg.)

~45 sec

< 20 sec

~30 sec

Recursive Proof Support

Audit Status

Multiple Public Audits

Ongoing Formal Verification

Multiple Public Audits

implement-zk-snarks
DEVELOPER GUIDE

Implementing zk-SNARKs with Circom and SnarkJS

This guide walks through building a privacy-preserving transaction system using the Circom language and SnarkJS toolkit, from circuit design to on-chain verification.

Zero-Knowledge Succinct Non-Interactive Arguments of Knowledge (zk-SNARKs) allow one party to prove they know a secret value satisfying certain constraints without revealing the value itself. This is foundational for privacy in blockchain, enabling private transactions, identity proofs, and confidential computations. The Circom domain-specific language is used to define the arithmetic circuit that encodes these constraints, while SnarkJS is a JavaScript library that handles the proving and verification process, generating the cryptographic proofs.

The first step is to define your circuit logic in a .circom file. A circuit is a set of constraints over signals (private and public variables). For a simple private transaction proving you have sufficient balance without revealing the amount, you might define constraints ensuring a new balance is non-negative and correctly derived from the old balance minus a secret spend. Install Circom and SnarkJS via npm: npm install -g circom snarkjs. Then, compile your circuit with circom circuit.circom --r1cs --wasm --sym to generate the R1CS constraint system and WebAssembly files.

Next, you need a trusted setup to generate the proving and verification keys. This involves a Phase 1 Powers of Tau ceremony and a circuit-specific Phase 2 setup. For development, you can use a pre-generated Powers of Tau file. Run snarkjs powersoftau new bn128 12 pot12_0000.ptau to start, then contribute and prepare it. Finally, generate the zkey file with snarkjs groth16 setup circuit.r1cs pot12_final.ptau circuit_0000.zkey. For production, a multi-party ceremony is essential to maintain trustlessness.

With the setup complete, you can generate proofs. Using the WebAssembly witness calculator (circuit.wasm), compute the witness for your specific inputs (private spend amount, old balance). Then, generate the proof with snarkjs groth16 prove circuit_0000.zkey witness.wtns proof.json public.json. The proof.json contains the actual zk-SNARK proof, and public.json holds the public signals (e.g., the new, public balance). You can verify the proof offline using snarkjs groth16 verify verification_key.json public.json proof.json.

To use this on-chain, you need a verifier smart contract. SnarkJS can generate a Solidity contract: snarkjs zkey export solidityverifier circuit_0000.zkey verifier.sol. This contract contains a verifyProof function. Deploy this contract to your chosen EVM chain. Your application contract (e.g., a private payment pool) will call this verifier, passing the proof and public signals. If the verification passes, the contract logic (e.g., transferring funds) executes. This creates a fully functional, privacy-first transaction framework where the blockchain only sees the public outcome and a valid proof.

Key considerations for production include the cost of on-chain verification (Groth16 is relatively gas-efficient), the security of the trusted setup, and circuit optimization to minimize constraints and proving time. Always audit your Circom circuits for logical errors, as bugs can compromise privacy or correctness. Resources like the Circom documentation and community repositories provide essential reference material for advanced patterns and best practices.

implement-ring-signatures
TUTORIAL

Building Ring Signatures for Sender Privacy

A technical guide to implementing ring signatures, a cryptographic primitive that provides strong anonymity for transaction senders in blockchain systems.

Ring signatures enable a user to sign a message on behalf of a "ring" or group, making it cryptographically impossible to determine which specific member produced the signature. This provides strong sender anonymity by decoupling the signer's identity from the transaction. Unlike group signatures, ring signatures have no group manager and require no setup ceremony, making them ideal for decentralized, permissionless environments like public blockchains. The core property is signer ambiguity: an external verifier can confirm the signature is valid and was created by a ring member, but cannot identify the actual signer.

The most common construction is the linkable ring signature (LRS), which adds a critical security feature for preventing double-spends. In an LRS scheme, each signature also generates a unique "key image" derived from the signer's private key. While the signature itself is anonymous, the key image is publicly verifiable and unique per spent output. If a user tries to sign two different transactions with the same private key, they will produce identical key images, allowing the network to detect and reject the double-spend attempt. This mechanism is fundamental to privacy-preserving cryptocurrencies like Monero, which uses the CryptoNote protocol.

To implement a basic ring signature, you typically work with elliptic curve cryptography. A common approach uses the Ed25519 curve. The process involves several steps: key generation for each ring member, signature construction using a combination of the real signer's private key and randomly generated values for the other ring members (forming a ring of public keys), and signature verification where anyone can check the mathematical proof without learning the signer's identity. Libraries like ringct in Monero or bulletproofs provide optimized implementations.

When setting up a privacy-first transaction framework, you must carefully manage the ring members (the set of possible past transaction outputs). A larger ring size increases anonymity but also increases computational cost and transaction size. For example, Monero currently uses a mandatory ring size of 16. The selection of decoy outputs is critical; a naive random selection from the global pool can be statistically analyzed. Advanced implementations use temporal decay or output age algorithms to mimic real spending behavior and resist chain analysis.

Developers must also consider the interaction with other privacy components. Ring signatures typically hide the sender, but additional techniques are needed for full privacy: Stealth Addresses hide the receiver by generating a one-time destination address for each transaction, and Confidential Transactions hide the transaction amount using Pedersen Commitments and range proofs. Combining these with ring signatures creates a robust privacy suite, as seen in protocols like Mimblewimble (used by Grin and Beam) and Lelantus.

For practical integration, audit existing libraries rather than building from scratch. Review the Monero Research Lab papers for formal security proofs. Test with small ring sizes in a devnet first, and use a trusted setup if your scheme requires it (though many modern LRS schemes are setup-free). Remember that privacy is a system property; even a perfect ring signature implementation can be undermined by metadata leaks, unencrypted mempools, or improper wallet behavior.

implement-stealth-addresses
TUTORIAL

Integrating Stealth Addresses for Recipient Privacy

A technical guide to implementing stealth addresses, a cryptographic protocol that enhances recipient privacy by generating unique, one-time deposit addresses for each transaction.

Stealth addresses are a privacy-enhancing technology designed to break the on-chain link between a sender and a recipient. Unlike a standard Ethereum transaction where the recipient's public address is visible on the blockchain, a stealth address system allows a sender to generate a unique, one-time deposit address for each payment. Only the intended recipient, using their private stealth meta-address, can derive the corresponding private key to control the funds. This prevents third-party observers from linking multiple transactions to the same recipient, significantly improving financial privacy. The concept is a core component of privacy-focused ecosystems like Monero and is being actively integrated into the EVM landscape through standards like ERC-5564.

The cryptographic foundation relies on elliptic curve cryptography, typically the secp256k1 curve used by Ethereum. A recipient's stealth meta-address is a public identifier from which countless stealth addresses can be derived. The process involves three key steps: key generation, stealth address derivation, and key revelation. First, the sender uses the recipient's stealth meta-address and a random nonce to compute a shared secret. This secret is then used to generate a unique, ephemeral Ethereum address—the stealth address—where funds are sent. The sender also publishes a stealth meta-transaction containing cryptographic hints, allowing only the recipient to scan the chain and discover their new assets.

To set up a privacy-first framework, developers must integrate a stealth address library. For EVM chains, the ERC-5564: Stealth Address Registry standard provides a foundational interface. A practical implementation involves using a library like stealth-address-js from the Ethereum Foundation. The core workflow for a sender is to call generateStealthAddress(stealthMetaAddress, ephemeralPrivateKey), which returns the destination stealth address and the required viewingKey data to broadcast. For the recipient, a scanning service must monitor the Stealth Address Registry or relevant events, using their private spend key to test each new announcement and derive control of any funds sent to them.

Here is a simplified code snippet demonstrating address generation using a hypothetical library:

javascript
import { generateStealthAddress, SECP256K1 } from '@stealth-address/lib';

// Recipient's public stealth meta-address (shared publicly)
const stealthMetaAddress = '0x02...';

// Sender generates a random ephemeral private key
const ephemeralPrivateKey = SECP256K1.generateRandomPrivateKey();

// Generate the one-time stealth address and announcement data
const { stealthAddress, viewingPublicKey } = generateStealthAddress(
  stealthMetaAddress,
  ephemeralPrivateKey
);

// Send funds to `stealthAddress`
// Broadcast `viewingPublicKey` and `ephemeralPublicKey` via a registry

The recipient would then scan announcements, compute the shared secret, and derive the private key for stealthAddress.

Key challenges in integration include managing gas costs for on-chain announcements, ensuring reliable off-chain scanning infrastructure for recipients, and achieving broad wallet interoperability. Best practices involve using a canonical singleton registry (like the one deployed for ERC-5564) to avoid fragmentation, implementing efficient batch scanning, and providing clear user UX for managing stealth meta-addresses. Future developments focus on ZK-SNARKs to make scanning more efficient and cross-chain stealth addresses using protocols like Chainlink CCIP. For production use, audit the underlying cryptographic libraries and refer to the official ERC-5564 specification.

TECHNICAL TRADEOFFS

Privacy vs. Auditability Framework

A comparison of architectural approaches for balancing transaction privacy with compliance and audit requirements in blockchain applications.

Feature / MetricFull Privacy (e.g., Aztec, Zcash)Selective Disclosure (e.g., Tornado Cash Nova)Transparent Ledger (e.g., Base Ethereum)

Transaction Data Visibility

Fully shielded

Sender/recipient shielded, amount visible

Fully public

On-Chain Audit Trail

Partial (asset flow only)

Regulatory Compliance Feasibility

Requires viewing keys or proof systems

Possible with compliance tool integration

Native

Gas Overhead

High (~500k-1M gas)

Medium (~200k-500k gas)

Low (~21k gas)

Developer Integration Complexity

High

Medium

Low

Trust Assumptions

Cryptographic only

Trusted relay or operator

None (trustless)

Typical Finality Time

~10-20 minutes

~5-10 minutes

< 1 minute

Suitable Use Case

Private payroll, confidential DAO voting

Privacy-preserving DeFi, compliant withdrawals

Public goods funding, transparent treasuries

system-architecture
SYSTEM ARCHITECTURE AND INTEGRATION

Setting Up a Privacy-First Transaction Framework

This guide details the architectural components and integration patterns for building a system that protects user transaction data on public blockchains.

A privacy-first transaction framework shifts the paradigm from transparent, on-chain data exposure to selective disclosure. Core architectural components include a privacy layer (like Aztec, zkSync's ZK Stack, or Polygon Miden), a relayer network for submitting private transactions, and a user-facing application with a secure wallet (e.g., a browser extension). The system's goal is to allow users to prove the validity of a transaction—such as having sufficient funds—without revealing the sender, recipient, or amount to the public ledger. This is fundamentally different from mixing services, which obfuscate transaction trails but leave cleartext data on-chain.

Integration begins with selecting a privacy-enabling technology. For ZK-Rollups like Aztec, you integrate an SDK (like the Aztec.nr framework) to compile your private smart contract logic into zero-knowledge circuits. The application front-end then uses this SDK to generate ZK proofs locally in the user's browser, ensuring sensitive data never leaves their device. A critical backend service, the relayer, is required to pay network fees on the user's behalf, as the user's identity and funds are hidden. You can run your own relayer or use a service like Biconomy for gas abstraction.

Key design considerations involve managing privacy sets and note management. In UTXO-based models (common in ZK systems), assets are represented as encrypted 'notes.' Your application must securely store and sync these notes—often using a dedicated note management API or a local encrypted database. The size of the anonymity set, or the pool of possible transaction participants, directly impacts privacy; larger, more active applications provide stronger cover. Furthermore, you must design for selective disclosure, allowing users to reveal specific transaction details to auditors or regulators via viewing keys, without compromising their entire history.

For developers, a practical integration flow involves: 1) Writing a private smart contract in a domain-specific language (e.g., Noir for Aztec), 2) Deploying the contract's verification key to the L1, 3) Building a front-end that uses the aztec.js library to create and prove transactions, and 4) Configuring a relayer to broadcast the proof and public inputs. Testing is done on a local sandbox (like the Aztec Sandbox) before moving to a testnet. Remember, while the computation is private, transaction fees and the act of interacting with the contract are still public metadata that must be considered in your threat model.

PRIVACY-FIRST DEVELOPMENT

Frequently Asked Questions

Common questions and solutions for developers implementing privacy-preserving transaction frameworks using zero-knowledge proofs and stealth addresses.

Privacy refers to hiding transaction details (amount, asset type) from public view, while anonymity conceals the link between a transaction and a real-world identity. Most blockchains like Ethereum offer pseudonymity, not true privacy, because all transaction data is public. Privacy-first frameworks use cryptographic techniques like zero-knowledge proofs (ZKPs) to prove a transaction is valid without revealing its details, and stealth addresses to break the on-chain link between sender and receiver. For example, Zcash uses zk-SNARKs to shield transaction values, and Aztec Network uses ZK rollups for private DeFi.

conclusion
FRAMEWORK INTEGRATION

Conclusion and Next Steps

You have now implemented the core components of a privacy-first transaction framework. This final section consolidates your setup and outlines practical next steps for development and deployment.

Your framework now integrates zero-knowledge proofs (ZKPs) via tools like zk-SNARKs in Circom or zk-STARKs with StarkWare, confidential assets using protocols such as Aztec or Zcash's zk-Sapling, and transaction mixing through services like Tornado Cash or Railgun. The key is to understand the trade-offs: ZKPs offer strong privacy but require complex setup and verification, while mixing pools provide liquidity but introduce trust assumptions. Always map your privacy requirements—whether for shielding transaction amounts, obfuscating sender/receiver links, or both—to the appropriate cryptographic primitive. Test each component in a local development environment like Hardhat or Foundry before considering mainnet deployment.

For ongoing development, focus on gas optimization and user experience. Privacy-enhancing transactions are computationally intensive; benchmark your smart contracts using tools like eth-gas-reporter. Consider implementing meta-transactions or account abstraction (ERC-4337) to allow users to pay fees in stablecoins or have sponsors cover costs, lowering the barrier to entry. Furthermore, design clear front-end interfaces that educate users on privacy guarantees without overwhelming them with technical jargon. Documentation is critical; provide clear guides for integrating your framework with popular wallets (MetaMask, WalletConnect) and dApp frameworks (Next.js, Vite).

The next step is to rigorously audit your system. Engage with specialized security firms like Trail of Bits, OpenZeppelin, or CertiK that have experience with zero-knowledge circuits and privacy protocols. Concurrently, participate in testnet deployments on networks like Sepolia or Goerli to gather real-world data on reliability and fees. Explore advanced topics such as privacy-preserving DeFi (e.g., using Aztec Connect for private swaps) or cross-chain privacy using bridges like zkBridge. Finally, stay updated with evolving standards like EIP-7503 for ZKP verification and monitor Layer 2 solutions like zkSync Era or Scroll that offer native ZK-rollup privacy features.