Cryptography provides the mathematical foundation for privacy in Web3, allowing users and applications to prove statements or compute over data without revealing the underlying information. Unlike simple encryption that just scrambles data, advanced privacy-preserving techniques like zero-knowledge proofs (ZKPs) enable verification of a claim's truth without disclosing the data itself. For instance, a user can prove they are over 18 without revealing their birth date, or a protocol can verify a transaction is valid without exposing the sender, receiver, or amount. This shift from data transparency to computational integrity is fundamental to private smart contracts and confidential DeFi.
How to Use Cryptography for Privacy
How to Use Cryptography for Privacy
This guide explains the core cryptographic primitives—zero-knowledge proofs, homomorphic encryption, and secure multi-party computation—that enable privacy in blockchain applications.
Zero-knowledge proofs, particularly zk-SNARKs and zk-STARKs, are the most prominent tools for blockchain privacy. A zk-SNARK allows a prover to generate a small proof that a computation was performed correctly, which any verifier can check almost instantly. In practice, this is implemented using circuits. For example, the Circom library allows developers to define a private transaction circuit:
circomtemplate PrivateTransfer() { signal input senderBalance; signal input amount; signal input senderPrivateKey; signal output newBalance; // Constraint: new balance = old balance - amount, and amount > 0 newBalance <== senderBalance - amount; amount > 0; }
This circuit enforces the logic of a transfer without revealing the inputs, generating a proof that can be posted on-chain. Projects like zkSync and Aztec use such systems to offer private transactions and scalable rollups.
Beyond ZKPs, homomorphic encryption (HE) and secure multi-party computation (MPC) offer complementary approaches. HE allows computations to be performed directly on encrypted data. A practical use case is private voting on-chain, where votes are encrypted but can still be tallied. MPC enables multiple parties to jointly compute a function over their private inputs without any party seeing the others' data; this is crucial for decentralized key generation and threshold signatures in wallet security. While HE and MPC are more computationally intensive than ZKPs and less common in production blockchains today, they represent active research areas for complex private computations like confidential decentralized machine learning.
Implementing cryptography correctly requires careful attention to trust assumptions and auditability. A system using zk-SNARKs often requires a trusted setup ceremony to generate public parameters, introducing a potential point of failure if compromised. Newer systems like zk-STARKs and some MPC protocols aim to be trustless. Furthermore, while the data is private, the logic of the circuit or program is public and must be thoroughly audited for bugs, as flaws can lead to loss of funds or incorrect proofs. Developers should use well-audited libraries like arkworks for Rust or snarkjs for JavaScript, and always consider the trade-offs between proof size, verification speed, and setup requirements for their specific application.
How to Use Cryptography for Privacy
This guide covers the cryptographic foundations for building privacy-preserving applications in Web3, from basic encryption to advanced zero-knowledge proofs.
Privacy in blockchain systems is not about anonymity but about selective disclosure. Core cryptographic primitives enable this: public-key cryptography for secure communication, hash functions for data integrity, and digital signatures for authentication. For example, when you generate an Ethereum wallet, you create a private key (kept secret) and a derived public address (shared publicly). This asymmetric relationship allows you to prove ownership of assets without revealing the secret key, forming the basis for pseudonymous interaction on-chain.
To move beyond pseudonymity, developers use more advanced techniques. Commitment schemes allow you to commit to a value (like a bid or a vote) without revealing it, later proving you acted on that committed value. Zero-knowledge proofs (ZKPs), such as zk-SNARKs or zk-STARKs, enable one party (the prover) to convince another (the verifier) that a statement is true without revealing any information beyond the statement's validity. This is foundational for private transactions in protocols like Zcash or for verifying identity credentials without exposing personal data.
Implementing these concepts requires understanding specific libraries and frameworks. For elliptic curve cryptography and hashing, use well-audited libraries like libsecp256k1 (used by Bitcoin and Ethereum) or @noble/curves in JavaScript. For zero-knowledge development, toolkits like Circom (for writing ZKP circuits) and SnarkJS (for proof generation and verification) are essential. Always use these tools within secure, non-custodial architectures to ensure private keys never leave a user's device, typically managed by wallets or Hardware Security Modules (HSMs).
A critical application is private state management. Instead of storing plaintext data on-chain, applications store cryptographic commitments or hashes. User-specific data, encrypted with their public key, can be stored off-chain (e.g., on IPFS or a secure server), with only the content identifier (CID) or a state root posted to the blockchain. Users can then generate ZKPs to prove their encrypted data satisfies certain conditions (e.g., "I am over 18") when interacting with a smart contract, without revealing the underlying data.
Security considerations are paramount. Cryptographic agility—the ability to upgrade algorithms as standards evolve—is crucial for long-term privacy. Avoid designing custom cryptography; instead, rely on battle-tested implementations. Be aware of metadata leakage; even with encrypted content, transaction patterns, timing, and amounts can reveal information. Techniques like coin mixing (e.g., Tornado Cash) or confidential transactions aim to obscure this metadata. Always conduct formal audits for any privacy-centric code before mainnet deployment.
Core Cryptographic Privacy Concepts
Essential cryptographic primitives that enable private transactions, confidential computation, and data protection on public blockchains.
Commitment Schemes
Cryptographic protocols that allow a user to commit to a chosen value while keeping it hidden, with the ability to reveal it later. This is a core building block for privacy-preserving protocols.
- Pedersen Commitments are additively homomorphic, allowing commitments to sums of values to be computed without revealing the individual amounts. Used in confidential transactions.
- Merkle Tree Commitments enable proving membership of an element in a set without revealing the entire set, crucial for privacy-preserving airdrops or voting.
Multi-Party Computation (MPC)
A cryptographic technique that enables a group of parties to jointly compute a function over their private inputs without revealing those inputs to each other. It decentralizes trust for private key management and computation.
- Threshold Signature Schemes (TSS) are a key application, where a private key is split among multiple parties, requiring a threshold (e.g., 2-of-3) to sign a transaction. This enhances wallet security.
- Used for secure wallet custody (Fireblocks, ZenGo), private auctions, and federated learning on sensitive data.
Ring Signatures
A type of digital signature where a signer from a group can produce a signature on behalf of the entire "ring," making it computationally infeasible to determine which member's key was used to sign. This provides plausible deniability.
- CryptoNote Protocol, used by Monero, employs ring signatures to obfuscate the source of a transaction by mixing the real input with several decoys from the blockchain.
- Unlike ZKPs, ring signatures provide privacy through obfuscation within a set rather than cryptographic proof of validity without disclosure.
Implementing Zero-Knowledge Proofs
A developer-focused tutorial on integrating zero-knowledge cryptography for privacy and scalability in blockchain applications.
Zero-knowledge proofs (ZKPs) are cryptographic protocols that allow one party (the prover) to convince another party (the verifier) that a statement is true without revealing any information beyond the validity of the statement itself. This is foundational for building private and scalable Web3 applications. The two primary types are zk-SNARKs (Succinct Non-interactive Arguments of Knowledge), known for their small proof size and fast verification, and zk-STARKs (Scalable Transparent Arguments of Knowledge), which offer post-quantum security without a trusted setup. Choosing between them involves trade-offs in proof size, verification speed, and setup requirements.
To implement ZKPs, developers typically work with high-level domain-specific languages (DSLs) and compilers that abstract the complex underlying math. Popular frameworks include Circom, which uses a circuit programming language, and ZoKrates, a toolbox for the Ethereum ecosystem. The workflow involves three core steps: 1) Defining the computational statement as an arithmetic circuit, 2) Generating a proving key and a verification key (often via a trusted setup ceremony for SNARKs), and 3) Using these keys to create and verify proofs off-chain or on-chain. For example, you can prove you know the pre-image of a hash without revealing it.
A common application is creating a private transaction. Using Circom, you might define a circuit that checks a Merkle tree inclusion proof for a note commitment and validates a nullifier. After compiling the circuit and running a trusted setup, you generate a proving key (proving_key.zkey) and verification key (verification_key.json). A user's client can then create a proof using witness data, and a Solidity verifier contract, generated from the verification key, can validate the proof on-chain for less than 500k gas, enabling private actions.
For scalable rollups, ZKPs are used to prove the correctness of batched transactions. A sequencer processes hundreds of transfers, executes them to produce a new state root, and generates a validity proof (a zk-SNARK or zk-STARK) attesting to the correct state transition. This single proof is then posted to Ethereum Layer 1. Verifying this proof is significantly cheaper and faster than re-executing all transactions, which is why projects like zkSync, StarkNet, and Polygon zkEVM can offer high throughput and low fees while inheriting Ethereum's security.
When implementing ZKPs, key considerations include the trusted setup (a critical security ceremony for SNARKs), circuit complexity (which directly impacts proof generation time and cost), and verifier cost (the gas required for on-chain verification). Always audit your circuits and use well-tested libraries. For further learning, explore the documentation for Circom and ZoKrates, or review real-world code from the Tornado Cash circuits (for educational purposes) to understand advanced patterns.
Creating Stealth Addresses
A technical guide to implementing stealth addresses, a cryptographic method for enhancing on-chain privacy by generating unique, one-time receiving addresses.
Stealth addresses are a privacy-enhancing technology designed to break the linkability of transactions on public blockchains. On networks like Ethereum or Bitcoin, a user's public address is typically reused, allowing anyone to trace their entire transaction history and balance. A stealth address protocol enables a sender to generate a unique, one-time destination address for a recipient on the fly. Only the intended recipient, using their private view key and spend key, can detect and spend funds sent to these ephemeral addresses. This creates a powerful privacy property: all payments to a single individual appear to go to unrelated, random addresses, obscuring the recipient's financial activity.
The core mechanism relies on elliptic curve cryptography, typically using the secp256k1 curve common in blockchain systems. A recipient has a static stealth meta-address, which is publicly shared and consists of two public keys: a view public key (P_v) and a spend public key (P_s). When a sender wants to make a private payment, they generate a random secret r (an ephemeral private key). They then compute a shared secret s = r * P_v using Elliptic Curve Diffie-Hellman (ECDH). This shared secret is hashed to derive a stealth public key for the transaction: P_stealth = P_s + hash(s) * G, where G is the generator point. The corresponding stealth private key, which only the recipient can compute, is p_stealth = p_s + hash(s), where p_s is the recipient's private spend key.
To enable the recipient to find incoming payments, the sender must publish a stealth hint, often called a view tag or included in the transaction data. This typically includes the ephemeral public key R = r * G. By scanning the blockchain, the recipient uses their private view key p_v to compute the same shared secret: s = p_v * R. They then check if any newly created addresses match the derived P_stealth. If a match is found, they can compute the private key and control the funds. This process, known as transaction scanning, allows recipients to manage an unlimited number of addresses with a single meta-address, without any interaction or pre-coordination with senders.
Implementing stealth addresses presents several challenges. The need for recipients to scan the entire blockchain for potential payments is computationally intensive. Solutions like view tags—where a small part of the shared secret hash is published—allow for efficient filtering, reducing scan time by over 99%. Furthermore, the protocol must handle edge cases like ensuring the derived stealth private key is valid (non-zero and within the curve's order) and managing key derivation in a secure, deterministic manner. Early implementations can be found in cryptocurrencies like Monero and in emerging Ethereum standards like ERC-5564: Stealth Addresses, which aims to standardize the scheme for EVM chains.
For developers, integrating stealth addresses involves careful cryptographic implementation. Below is a simplified Python pseudocode example using the secp256k1 library, demonstrating the core address generation and scanning logic.
pythonimport hashlib from secp256k1 import PrivateKey, PublicKey # Recipient's keys (generated once) priv_view = PrivateKey() priv_spend = PrivateKey() pub_view = priv_view.pubkey pub_spend = priv_spend.pubkey # SENDER: Generate stealth address for recipient def generate_stealth_address(pub_view, pub_spend): r = PrivateKey() # Ephemeral private key R = r.pubkey # Ephemeral public key (stealth hint) shared_secret = r.ecdh(pub_view) s = hashlib.sha256(shared_secret).digest() s_int = int.from_bytes(s, 'big') P_stealth = pub_spend.combine(PublicKey.from_secret(s_int)) return P_stealth, R # RECIPIENT: Scan for own stealth addresses def scan_transaction(R, priv_view, pub_spend): shared_secret = priv_view.ecdh(R) s = hashlib.sha256(shared_secret).digest() s_int = int.from_bytes(s, 'big') P_stealth = pub_spend.combine(PublicKey.from_secret(s_int)) # Check if P_stealth exists in transaction outputs return P_stealth
The primary use case for stealth addresses is enhancing privacy for public donations, payroll, or any transaction where the recipient's identity or total holdings must be concealed. When combined with other privacy technologies like zero-knowledge proofs or coin mixers, stealth addresses form a robust privacy suite. However, they are not a silver bullet; metadata analysis and patterns in transaction timing or value can still leak information. The ongoing development of standards like ERC-5564 is critical for interoperability, allowing wallets and dApps across the Ethereum ecosystem to adopt a unified approach to private payments, moving beyond the transparent default that currently dominates Web3.
Building Confidential Transactions
Confidential transactions use cryptographic proofs to hide transaction amounts and asset types on public blockchains, enabling privacy for financial activity.
Confidential transactions are a cryptographic protocol that allows users to prove a transaction is valid—without revealing the amount being sent or the type of asset involved. This is achieved using commitment schemes and zero-knowledge proofs (ZKPs). Unlike fully anonymous systems like Zcash, which hide all metadata, confidential transactions can be selectively applied to specific data fields, offering a balance between auditability and privacy. The core innovation is proving that inputs equal outputs (preventing inflation) and that amounts are non-negative, all while keeping the numbers themselves secret.
The most common implementation uses Pedersen Commitments and Bulletproofs. A Pedersen Commitment C = r*G + v*H encrypts the value v (the amount) with a blinding factor r. G and H are independent generator points on an elliptic curve. The sender creates commitments for input and output amounts. To prevent creating money out of thin air, they generate a range proof (e.g., using Bulletproofs) to cryptographically prove that each committed value v is within a valid range (e.g., 0 to 2^64), ensuring no negative amounts are created.
Monero's Ring Confidential Transactions (RingCT) is the most prominent real-world use case, deployed since 2017. RingCT combines confidential transactions with ring signatures to hide both the amount and the sender's identity. In a RingCT transaction, the network verifies that the sum of committed input amounts equals the sum of committed output amounts, and that all amounts are positive, without learning the actual figures. This prevents blockchain analysis from tracing payment flows based on transaction size, a significant weakness of transparent chains like Bitcoin.
For developers, libraries like libsecp256k1-zkp (used by Elements Project and Liquid Network) provide the cryptographic primitives. Here's a conceptual flow for creating a confidential transaction:
- For each amount
v, generate a random blinding factorr. - Compute the Pedersen Commitment:
C = r*G + v*H. - For each output commitment, generate a Bulletproof range proof.
- In the transaction, publish the commitments
Cand range proofs instead of plaintext amounts. - Provide a surplus blinding factor to balance the equation
∑input r = ∑output r, proving no new money was created.
Key challenges include transaction size (range proofs can be large, though Bulletproofs++ reduce this) and regulatory compliance. Some protocols, like the Liquid Network's Confidential Assets, allow for selective disclosure of transaction details to authorized auditors using asset surjection proofs and viewing keys. This enables enterprises to use private transactions while satisfying audit requirements, showcasing how cryptographic privacy can coexist with necessary transparency.
Privacy Technique Comparison
Comparison of core cryptographic techniques used for on-chain privacy, detailing their mechanisms, trade-offs, and typical applications.
| Feature | Zero-Knowledge Proofs (ZKPs) | Commitment Schemes | Trusted Execution Environments (TEEs) |
|---|---|---|---|
Cryptographic Principle | Proof of knowledge without revealing data | Hiding data with a binding commitment | Hardware-enforced secure computation |
Privacy Guarantee | Computational (cryptographic) | Computational (hashing) | Hardware-based trust |
Data Integrity Proof | |||
Transaction Linkability | Depends on implementation | ||
On-Chain Verification Cost | High (10k-100k+ gas) | Low (< 10k gas) | Low (off-chain verification) |
Primary Use Case | Private transactions (zkRollups), identity | Blind auctions, voting | Confidential smart contracts, oracles |
Trust Assumption | Trustless (cryptography) | Trustless (cryptography) | Trusted hardware manufacturer |
Example Protocol | zkSync, Aztec | Commit-Reveal voting schemes | Oasis Network, Secret Network |
Tools and Libraries
Implement privacy in your Web3 applications using these cryptographic primitives and libraries. This guide covers zero-knowledge proofs, secure multi-party computation, and confidential transactions.
Common Implementation Mistakes
Cryptography is essential for building private applications, but subtle errors can completely undermine security guarantees.
A foundational mistake is confusing confidentiality with privacy. Confidentiality ensures data is encrypted so only authorized parties can read it. Privacy is a broader concept about minimizing the exposure of sensitive information, including metadata like transaction amounts or participant identities. Using encryption (confidentiality) without considering what data is revealed on-chain (privacy) is a critical oversight. For example, a smart contract might store encrypted user data, but if the contract logic leaks which users are interacting or the frequency of their actions, privacy is compromised.
Developers often misuse or misunderstand zero-knowledge proofs (ZKPs). A common error is proving a statement that is not cryptographically sound, like proving knowledge of a preimage for a hash without binding it to a specific context, allowing replay attacks. Another pitfall is using non-standard or unaudited cryptographic libraries (like snarkjs alternatives) which may contain bugs or insecure parameter generation. Always use well-established, audited libraries such as circom with trusted setups or arkworks for more advanced constructions, and rigorously define what your proof actually attests.
Improper key management persistently plagues private systems. Storing private keys or sensitive randomness in client-side JavaScript is highly vulnerable. For web applications, consider using specialized enclaves or Trusted Execution Environments (TEEs) for key operations, or decentralized solutions like threshold signature schemes to distribute trust. Never derive keys from weak entropy sources; use cryptographically secure random number generators like getRandomValues() in browsers or the secrets module in Node.js. Key rotation and revocation mechanisms are frequently absent but are necessary for long-term security.
Failing to protect metadata is perhaps the most pervasive privacy leak. On a public blockchain, patterns in transaction timing, gas fees, and interaction with specific smart contracts can deanonymize users. Techniques like commit-reveal schemes, where a user first submits a hash of their action and later reveals it, can obscure timing. Mixing protocols or zk-SNARKs-based anonymous transactions (e.g., Tornado Cash, Aztec) break the link between sender and receiver. However, implementing these requires careful design to avoid side-channel data leakage through the contract's public state changes.
Finally, a lack of formal verification or comprehensive audit for custom cryptographic logic is a high-risk mistake. Cryptographic protocols are brittle; a small logical error can render the entire system insecure. Always subject your implementation to professional audits by firms specializing in cryptography. Use specification languages and verification tools like Zebra for Circom circuits or Halo2's proving system to mathematically check for correctness. Privacy is not a feature you can add later—it must be designed correctly from the first line of code.
Frequently Asked Questions
Common developer questions about implementing cryptographic privacy in Web3 applications, covering zero-knowledge proofs, stealth addresses, and secure transaction design.
zk-SNARKs (Zero-Knowledge Succinct Non-Interactive Argument of Knowledge) and zk-STARKs (Zero-Knowledge Scalable Transparent Argument of Knowledge) are both zero-knowledge proof systems, but with key trade-offs.
zk-SNARKs (used by Zcash, Aztec):
- Require a trusted setup ceremony to generate public parameters, creating a potential security risk.
- Have very small proof sizes (~200 bytes) and fast verification.
- Are computationally intensive for the prover.
zk-STARKs (used by StarkNet):
- Are transparent, requiring no trusted setup.
- Generate larger proof sizes (tens of kilobytes).
- Offer better scalability for the prover and are believed to be quantum-resistant.
For privacy applications, SNARKs are often chosen for their succinct proofs on-chain, while STARKs are preferred where trust minimization is paramount and larger proof sizes are acceptable.
Resources and Further Reading
These resources focus on practical cryptographic techniques used to build private-by-design systems. Each card links to primary documentation or research-grade material suitable for implementation and protocol analysis.
Conclusion and Next Steps
This guide has explored the cryptographic foundations for privacy in Web3, from zero-knowledge proofs to stealth addresses. The next step is to apply these concepts in practice.
Implementing cryptographic privacy is not a single solution but a layered approach. For on-chain data, zero-knowledge proofs (ZKPs) like zk-SNARKs or zk-STARKs allow you to prove transaction validity without revealing underlying details—essential for private voting or confidential DeFi positions. For identity and interactions, stealth addresses and semaphore-style group anonymity sets break the link between a user's public identity and their on-chain actions. Each tool addresses a specific privacy leak, and combining them creates a robust privacy shield.
To start building, choose a framework that matches your application's needs. For ZK application logic, explore Circom for circuit design or Noir for a more developer-friendly experience. Libraries like zkp.js or snarkjs provide the proving systems. For identity privacy, the Semaphore protocol offers a tested framework for anonymous signaling, while Tornado Cash's circuit code (available on GitHub) serves as a canonical example of a privacy pool. Always audit your circuits with tools like Picus or Veridise before mainnet deployment.
The regulatory and ethical landscape for privacy-enhancing technologies (PETs) is evolving. While tools like Tornado Cash have faced sanctions, the underlying cryptography remains vital for legitimate use cases—protecting donor privacy in DAOs, securing business logic, or enabling confidential healthcare data oracles. Developers must implement compliance-ready privacy by designing systems that allow for selective disclosure via ZK proofs to authorized parties, ensuring applications are both private and responsible.
Your next practical steps should involve experimentation on a testnet. Deploy a simple Semaphore contract on Sepolia and create an anonymous group. Write a basic Circom circuit that proves knowledge of a hash preimage without revealing it, and generate proofs using the snarkjs CLI. Review the ZKP security checklist from 0xPARC to avoid common pitfalls like under-constrained circuits. Engaging with the research community through the ZKProof standardization effort or the Privacy & Scaling Explorations team will keep your knowledge current.
Ultimately, cryptography provides the tools, but privacy is a property of system design. A "private" dApp with a frontend that leaks IP addresses or uses centralized indexers fails its goal. Consider the entire stack: use Tor or VPNs for RPC access, leverage decentralized storage for metadata, and design incentive structures that don't compromise anonymity. By integrating these cryptographic primitives thoughtfully and holistically, developers can build the next generation of Web3 applications where user sovereignty is fundamentally protected.