smithery.ai

circom-dev

Zero-knowledge proof circuit development using circom.

First seen Mar 23, 2026

Installation

$ npx skills add https://smithery.ai

Summary

  • Zero-knowledge proof circuit development using circom.
  • Use when implementing arithmetic circuits for zkSNARKs, including circuit design, constraint verification, witness generation, and testing.
  • Triggers on tasks like "create a circom circuit", "implement ZK proof", "write Merkle tree circuit", "add range proof", or any zero-knowledge cryptography implementation requiring circom.

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery.ai · top by installs.

npx skills add https://smithery.ai

Browse all from smithery.ai

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 12,966 B
  • docs SUMMARY.md 400 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 1 installs

SKILL.md

Circom Development

Expert guidance for designing, implementing, and testing zero-knowledge proof circuits using circom.

Overview

This skill provides comprehensive support for circom circuit development:

  • Circuit Implementation: Design and write optimized arithmetic circuits
  • Constraint Verification: Ensure circuits are properly constrained and secure
  • Witness Generation: Create and test witness calculators
  • Testing: Comprehensive testing patterns for circuits
  • Best Practices: Security guidelines and optimization techniques

Quick Start

1. Project Setup

Initialize a new circom project with required dependencies:

# Copy package.json template
cp assets/package.json ./package.json

# Install dependencies
npm install

# Create project structure
mkdir -p circuits build scripts

2. Create Circuit

Use the circuit template as a starting point:

cp assets/template_circuit.circom circuits/your_circuit.circom

Edit the circuit with your logic:

pragma circom 2.0.0;
include "node_modules/circomlib/circuits/poseidon.circom";

template YourCircuit() {
    signal input in;
    signal output out;

    component hasher = Poseidon(1);
    hasher.inputs[0] <== in;
    out <== hasher.out;
}

component main = YourCircuit();

3. Compile Circuit

Use the compilation script:

bash scripts/compile_circuit.sh circuits/your_circuit.circom

This generates:

  • build/yourcircuitjs/your_circuit.wasm - Witness calculator
  • build/your_circuit.r1cs - Constraint system
  • build/your_circuit.sym - Symbol mapping

4. Setup Proving Keys

Generate zkey and verification key:

bash scripts/setup_keys.sh build/your_circuit.r1cs

This generates:

  • build/zkey/your_circuit.zkey - Proving key
  • build/zkey/verification_key.json - Verification key
  • build/zkey/yourcircuitverifier.sol - Solidity verifier

5. Create Test

Use the test template:

cp assets/template_test.js test.js

Update test inputs and run:

node test.js

Workflow Decision Tree

┌─────────────────────────────────────┐
│ What do you need to do?             │
└──────────────┬──────────────────────┘
               │
       ┌───────┴────────┐
       │                │
   New Circuit    Modify Existing
       │                │
       ▼                ▼
  Start from      Read existing
   template        circuit first
       │                │
       ▼                ▼
  Implement       Understand
  constraints     constraints
       │                │
       ▼                ▼
   Compile         Make changes
       │                │
       ▼                ▼
  Setup keys      Recompile
       │                │
       ▼                ▼
  Write tests     Update tests
       │                │
       └────────┬───────┘
                ▼
          Run & verify
                │
        ┌───────┴────────┐
        │                │
    Success         Failure
        │                │
        ▼                ▼
    Complete      Debug & fix
                        │
                        └──> Repeat

Circuit Design Guidelines

1. Define Requirements

Before writing code, clarify:

  • Private inputs: What information must remain secret?
  • Public inputs: What can be revealed to the verifier?
  • Outputs: What statement are you proving?
  • Constraints: What rules must be enforced?

Example: Password authentication

  • Private: password
  • Public: passwordHash
  • Statement: "I know a password that hashes to passwordHash"

2. Choose Components

Consult [circomlibcomponents.md](references/circomlibcomponents.md) for standard components:

  • Hashing: Poseidon, MiMC
  • Comparisons: IsZero, LessThan, IsEqual
  • Merkle Trees: SMTVerifier
  • Signatures: EdDSA

3. Write Constraints

Follow these principles:

Use <== for most operations (assigns AND constrains):

output <== input1 * input2;

Use === for explicit constraints:

component.out === expectedValue;

NEVER use <-- alone (no constraint):

// DANGEROUS - prover can cheat!
temp <-- unconstrained_value;

4. Validate Inputs

Always constrain input ranges:

// Ensure value is less than maximum
component check = LessThan(32);
check.in[0] <== value;
check.in[1] <== maxValue;
check.out === 1;

See [bestpractices.md](references/bestpractices.md) for security guidelines.

Common Circuit Patterns

Consult [circuitpatterns.md](references/circuitpatterns.md) for complete implementations:

Authentication

  • Password proof: Prove knowledge of password without revealing it
  • Credential verification: Prove possession of valid credentials

Merkle Trees

  • Membership proof: Prove element is in a set without revealing which
  • Tree update: Prove correct update of Merkle tree

Range Proofs

  • Value in range: Prove value is within bounds (e.g., age > 18)
  • Balance sufficiency: Prove sufficient balance without revealing amount

Voting

  • Anonymous voting: Vote without revealing identity
  • Weighted voting: Vote with weight based on holdings

Privacy

  • Private transfer: Transfer funds without revealing sender/receiver/amount
  • Nullifier pattern: Prevent double-spending

Testing Workflow

1. Unit Test Components

Test individual templates in isolation:

const circuit = await wasm_tester("circuits/component.circom");

// Test valid input
const input = { in: 10 };
const witness = await circuit.calculateWitness(input);
await circuit.checkConstraints(witness);

// Test expected output
await circuit.assertOut(witness, { out: 100 });

2. Test Edge Cases

Always test:

  • Zero values: { in: 0 }
  • Maximum values: Near field prime
  • Boundary conditions: Min/max range values
  • Invalid inputs: Should fail constraint checks

3. Integration Testing

Test full proof generation and verification:

const { proof, publicSignals } = await snarkjs.groth16.fullProve(
  input,
  wasmPath,
  zkeyPath
);

const vKey = JSON.parse(fs.readFileSync(vkeyPath));
const isValid = await snarkjs.groth16.verify(vKey, publicSignals, proof);
assert(isValid);

Use scripts/verify_proof.js for standalone verification:

node scripts/verify_proof.js -p proof.json -s public.json -v verification_key.json

Optimization Techniques

1. Minimize Constraints

Fewer constraints = faster proving time.

Check constraint count:

npx snarkjs r1cs info build/circuit.r1cs

Optimization tips:

  • Reuse components when possible
  • Minimize hash operations (expensive)
  • Use assert for compile-time checks (no runtime cost)
  • Combine operations where possible

2. Choose Efficient Components

  • Poseidon > MiMC: Poseidon is optimized for zkSNARKs
  • Bit operations: Use Num2Bits/Bits2Num for bit manipulation
  • Range checks: Use SafeLessThan for range-checked comparisons

3. Profile Circuit

Monitor statistics:

npx snarkjs r1cs info circuit.r1cs

Output shows:

  • Number of constraints
  • Number of public inputs/outputs
  • Number of private inputs
  • Number of wires

Security Checklist

Before deploying, verify:

  • All signals properly constrained (no <-- without verification)
  • Input ranges validated
  • Division operations properly constrained (with remainder check)
  • Public/private signals correctly specified
  • Edge cases tested (0, max values, boundaries)
  • No under-constrained circuits (verify constraint count)
  • Code reviewed
  • Static analysis tools run (Circomspect, PICUS if available)

See [bestpractices.md](references/bestpractices.md) for detailed security guidelines.

Troubleshooting

Common Issues

"Constraint doesn't match"

  • Check all signals are properly constrained with <== or ===
  • Verify arithmetic is correct
  • Look for signals using <-- without corresponding constraints

"Not enough values"

  • Ensure all inputs are provided in test
  • Check array sizes match template parameters

"Scalar size exceeds field size"

  • Input value is too large for the field
  • Use range constraints to validate inputs

High constraint count

  • Review circuit for optimization opportunities
  • Consider refactoring complex logic
  • Check for unnecessary component instantiations

Debugging Tips

  1. Add debug signals: Create intermediate signals to inspect values in witness
  2. Use circom logger: Add log() statements in circuit
  3. Test incrementally: Build circuit piece by piece, testing each addition
  4. Verify constraint count: Monitor constraint growth as you add logic

Scripts Reference

compile_circuit.sh

Compile circom circuits to WASM and R1CS.

./scripts/compile_circuit.sh <circuit_file> [options]

Options:
  -o, --output DIR    Output directory (default: build)
  -h, --help         Show help

setup_keys.sh

Generate proving and verification keys.

./scripts/setup_keys.sh <r1cs_file> [options]

Options:
  -s, --size N        Circuit size (default: 12)
  -o, --output DIR    Output directory (default: build/zkey)
  -p, --ptau DIR      ptau directory (default: ptau)
  -h, --help         Show help

verify_proof.js

Verify a zero-knowledge proof.

node scripts/verify_proof.js [options]

Options:
  -p, --proof FILE     Proof JSON file
  -s, --signals FILE   Public signals JSON file
  -v, --vkey FILE      Verification key file
  -h, --help          Show help

References

This skill includes detailed reference documentation:

[circomlibcomponents.md](references/circomlibcomponents.md)

Standard library component reference:

  • Hash functions (Poseidon, MiMC)
  • Comparators (IsZero, LessThan, IsEqual)
  • Multiplexers (Mux1, Mux3)
  • Bitwise operations (Num2Bits, Bits2Num)
  • Merkle trees (SMTVerifier)
  • Signatures (EdDSA)

[bestpractices.md](references/bestpractices.md)

Security and optimization guidelines:

  • Constraint writing best practices
  • Security considerations
  • Optimization techniques
  • Testing and debugging
  • Common pitfalls and how to avoid them

[circuitpatterns.md](references/circuitpatterns.md)

Implementation patterns for common use cases:

  • Authentication patterns
  • Merkle tree patterns
  • Range proof patterns
  • Voting patterns
  • Privacy-preserving patterns

Example: Complete Workflow

Here's a complete example of implementing a password authentication circuit:

// 1. Create circuit: circuits/password_auth.circom
pragma circom 2.0.0;
include "node_modules/circomlib/circuits/poseidon.circom";

template PasswordAuth() {
    signal input password;
    signal input passwordHash;

    component hasher = Poseidon(1);
    hasher.inputs[0] <== password;
    passwordHash === hasher.out;
}

component main {public [passwordHash]} = PasswordAuth();
# 2. Compile
bash scripts/compile_circuit.sh circuits/password_auth.circom

# 3. Setup keys
bash scripts/setup_keys.sh build/password_auth.r1cs
// 4. Create test: test_password.js
const snarkjs = require("snarkjs");
const circomlibjs = require("circomlibjs");

async function test() {
  // Calculate expected hash
  const password = 12345;
  const poseidon = await circomlibjs.buildPoseidon();
  const passwordHash = poseidon.F.toString(poseidon([password]));

  // Generate proof
  const { proof, publicSignals } = await snarkjs.groth16.fullProve(
    { password, passwordHash },
    "build/password_auth_js/password_auth.wasm",
    "build/zkey/password_auth.zkey"
  );

  // Verify
  const vKey = require("./build/zkey/verification_key.json");
  const isValid = await snarkjs.groth16.verify(vKey, publicSignals, proof);
  console.log("Valid:", isValid);
}

test();
# 5. Run test
node test_password.js

Additional Resources