Zero-Knowledge · 9 min read

Circom Tutorial:
Building Your First ZK Circuit

A hands-on guide to developing zero-knowledge circuits with Circom.

67ns
Proof Verify
SHA3-256
Hash
PQ
Secure
Zero
Knowledge Leaked

Circom is the most popular language for writing ZK circuits. This hands-on tutorial takes you from installation to your first working proof.

Installation

# Install Rust (if needed)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Install Circom
git clone https://github.com/iden3/circom.git
cd circom
cargo build --release
cargo install --path circom

# Install snarkjs
npm install -g snarkjs

Your First Circuit

Create a simple circuit that proves knowledge of factors:

// multiplier.circom
pragma circom 2.0.0;

template Multiplier() {
    // Private inputs (witness)
    signal private input a;
    signal private input b;

    // Public output
    signal output c;

    // Constraint: a * b must equal c
    c <== a * b;
}

component main = Multiplier();

Compiling the Circuit

# Compile to R1CS
circom multiplier.circom --r1cs --wasm --sym

# This generates:
# - multiplier.r1cs (constraint system)
# - multiplier_js/ (WASM for witness generation)
# - multiplier.sym (symbol file for debugging)

Trusted Setup

# Powers of tau ceremony (can reuse for circuits up to 2^n constraints)
snarkjs powersoftau new bn128 12 pot12_0000.ptau
snarkjs powersoftau contribute pot12_0000.ptau pot12_0001.ptau
snarkjs powersoftau prepare phase2 pot12_0001.ptau pot12_final.ptau

# Circuit-specific setup
snarkjs groth16 setup multiplier.r1cs pot12_final.ptau multiplier_0000.zkey
snarkjs zkey contribute multiplier_0000.zkey multiplier_final.zkey
snarkjs zkey export verificationkey multiplier_final.zkey verification_key.json

Generating a Proof

// Create input file: input.json
{ "a": 3, "b": 5 }

// Generate witness
node multiplier_js/generate_witness.js multiplier_js/multiplier.wasm input.json witness.wtns

// Generate proof
snarkjs groth16 prove multiplier_final.zkey witness.wtns proof.json public.json

Verifying the Proof

# Verify
snarkjs groth16 verify verification_key.json public.json proof.json
# Output: [INFO] OK!

What Was Proven

The prover demonstrated knowledge of a=3 and b=5 such that 3×5=15.
The verifier sees only that c=15 and that the proof is valid.
The values of a and b remain hidden.

More Complex Example: Age Verification

pragma circom 2.0.0;

include "circomlib/comparators.circom";

template AgeCheck() {
    signal private input birthYear;
    signal input currentYear;
    signal input minimumAge;
    signal output isOldEnough;

    component gte = GreaterEqThan(16);
    gte.in[0] <== currentYear - birthYear;
    gte.in[1] <== minimumAge;

    isOldEnough <== gte.out;
}

component main = AgeCheck();

Best Practices

Circom is the gateway to practical ZK development. Start simple, understand the workflow, then build more complex proofs.

Ready to Go Quantum-Secure?

Start protecting your users with post-quantum authentication today. 1,000 free auths, no credit card required.

Get Free API Key →

Build With Post-Quantum Security

Enterprise-grade FHE, ZKP, and post-quantum cryptography. One API call. Sub-millisecond latency.

Get Free API Key → Read the Docs
Free tier · 10,000 API calls/month · No credit card required
Verify It Yourself