Zero-knowledge proofs (ZKPs) are cryptographic methods that allow one party (the prover) to prove to another party (the verifier) that a statement is true without revealing any additional information beyond the validity of the statement itself. This tutorial will guide you through the fundamental concepts and help you create your first zero-knowledge proof.
Before diving in, you should have:
Basic understanding of cryptography concepts
Familiarity with programming (we'll use JavaScript/TypeScript)
Node.js installed on your system
Basic understanding of mathematical concepts
A zero-knowledge proof must satisfy three key properties:
Completeness: If the statement is true, an honest verifier will be convinced by an honest prover
Soundness: If the statement is false, no cheating prover can convince an honest verifier
Zero-knowledge: If the statement is true, the verifier learns nothing other than the fact that the statement is true
Interactive Zero-Knowledge Proofs (IZKPs)
Require back-and-forth communication between prover and verifier
Example: Schnorr protocol
Non-Interactive Zero-Knowledge Proofs (NIZKPs)
Single message from prover to verifier
Example: zk-SNARKs, zk-STARKs
Let's set up a basic project to work with zero-knowledge proofs. We'll use the circom
library, which is a popular choice for creating zero-knowledge circuits.
mkdir zk-proof-tutorial
cd zk-proof-tutorial
npm init -y
npm install circomlib snarkjs
Let's create a simple example: proving that you know a number that, when multiplied by itself, equals a given value, without revealing the original number.
Create a file named multiplier.circom
:
pragma circom 2.0.0;
template Multiplier() {
// Private input
signal private input a;
// Public input
signal input b;
// Output
signal output c;
// Constraint: a * a = b
c <== a * a;
b === c;
}
component main = Multiplier();
circom multiplier.circom --r1cs --wasm --sym
Create a file named generate-proof.js
:
const snarkjs = require("snarkjs");
const fs = require("fs");
async function generateProof() {
// The number we want to prove we know (private)
const a = 5;
// The public result (25)
const b = 25;
// Generate the proof
const { proof, publicSignals } = await snarkjs.groth16.fullProve(
{ a: a },
"multiplier.wasm",
"multiplier_final.zkey"
);
console.log("Proof:", proof);
console.log("Public signals:", publicSignals);
}
generateProof();
Create a file named verify-proof.js
:
const snarkjs = require("snarkjs");
async function verifyProof() {
const verificationKey = JSON.parse(fs.readFileSync("verification_key.json"));
const proof = JSON.parse(fs.readFileSync("proof.json"));
const publicSignals = JSON.parse(fs.readFileSync("public.json"));
const res = await snarkjs.groth16.verify(
verificationKey,
publicSignals,
proof
);
if (res === true) {
console.log("Verification OK");
} else {
console.log("Invalid proof");
}
}
verifyProof();
Let's break down what we just created:
Circuit Definition:
The circuit defines the constraints of our proof
We use signals to represent inputs and outputs
The constraint a * a = b
ensures the proof is valid
Proof Generation:
Takes private input (the number we know)
Generates a proof that we know this number
Outputs public signals (the result)
Proof Verification:
Verifies the proof without knowing the private input
Ensures the proof is valid and the constraints are satisfied
Zero-knowledge proofs have numerous applications:
Privacy-Preserving Transactions
Proving you have enough funds without revealing your balance
Example: Zcash cryptocurrency
Identity Verification
Proving you're over 18 without revealing your exact age
Proving you're a citizen without revealing your ID
Supply Chain
Security
Always use cryptographically secure random numbers
Keep private inputs secure
Use well-audited libraries
Performance
Optimize circuit size
Consider gas costs in blockchain applications
Use appropriate proving systems for your use case
Testing
Test with various inputs
Include edge cases
Verify proofs thoroughly
Circuit Complexity
Start with simple circuits
Break down complex problems into smaller components
Use existing libraries when possible
Gas Costs
Optimize circuit design
Consider using more efficient proving systems
Batch proofs when possible
Trusted Setup
Use existing trusted setups when possible
Consider transparent setups (zk-STARKs)
Participate in multi-party computation ceremonies
To continue your journey with zero-knowledge proofs:
Explore more complex circuits
Learn about different proving systems (zk-SNARKs, zk-STARKs)
Study real-world implementations
Contribute to open-source ZK projects
Join the zero-knowledge community
This tutorial has introduced you to the basics of zero-knowledge proofs and helped you create your first proof. Remember that ZKPs are a powerful tool for privacy and scalability, but they require careful implementation and understanding of the underlying concepts.
As you continue your journey, focus on understanding the mathematical foundations, practice with different types of proofs, and explore real-world applications. The field of zero-knowledge proofs is rapidly evolving, offering exciting opportunities for innovation and development.