Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 157 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
#
# snarkjs — zkSNARKs in JavaScript (Groth16, PLONK, FFLONK)
#
# Node.js / circom / Foundry-based development, test, and build.
#

SHELL = /bin/bash

# ── Top-level targets ─────────────────────────────────────────────────

.PHONY: all install build test test-smart-contracts test-forge test-all clean
.PHONY: circuits circuit-groth16 circuit-circuit2 circuit-plonk circuit-fflonk
.PHONY: verifier-preview
.PHONY: print-%

all: install build test

install:
npm install --no-audit --no-fund --loglevel=error
cd smart_contract_tests && npm install --no-audit --no-fund --loglevel=error

build:
npm run build

# ── Tests ─────────────────────────────────────────────────────────────

# Unit / integration tests (mocha). Covers:
# - Powers of Tau ceremony (full process)
# - Groth16 prove + off-chain verify
# - PLONK prove + off-chain verify
# - FFLONK prove + off-chain verify
# - Polynomial operations
# - Keypair derivation
test:
npm test

# Run a single mocha test file or grep pattern.
# make test-file FILE=test/fullprocess.js
# make test-grep GREP="Groth16 smart contract"
test-file:
npx mocha $(FILE)

test-grep:
npx mocha --grep "$(GREP)"

# Smart-contract (Hardhat) tests. Generates a Groth16 zkey from scratch,
# exports a Solidity verifier, compiles + deploys it via Hardhat, and
# calls verifyProof() on-chain. This is the test that validates EIP-197
# G2 encoding is correct end-to-end.
test-smart-contracts:
cd smart_contract_tests && npm test

# ── Forge (Foundry) EVM verification test ──────────────────────────────
#
# Lightweight on-chain verification test using Forge's built-in revm EVM
# — the SAME precompile engine that rejected the faulty G2 encoding.
#
# Auto-skips with exit code 0 if Forge is not installed. No npm deps
# beyond snarkjs itself (no Hardhat, no ethers, no waffle). A single
# static Foundry binary is the only external requirement.
#
# make test-forge # 1-input circuit (test/groth16)
# make test-forge-all # both 1-input and 3-input circuits
# make nix-test-forge # inside Nix environment
#
# Override circuit / ptau:
# make test-forge CIRCUIT_DIR=test/circuit2

test-forge:
bash scripts/forge_verify_test.sh

test-forge-all:
CIRCUIT_DIR=test/groth16 bash scripts/forge_verify_test.sh
CIRCUIT_DIR=test/circuit2 bash scripts/forge_verify_test.sh

# Run ALL tests: off-chain unit tests + on-chain smart-contract tests.
test-all: test test-smart-contracts

# ── Test circuits (circom → R1CS / WASM) ──────────────────────────────

# Most test circuits are checked in pre-compiled. Use these targets to
# recompile them after editing a .circom file.
#
# make circuits # recompile all test circuits
# make circuit-groth16 # recompile only the groth16 1-input circuit

CIRCUITS_DIR = test
CIRCOM = circom
CIRCOM_OPTS = --r1cs --wasm --sym

circuits: circuit-groth16 circuit-circuit2 circuit-plonk circuit-fflonk

circuit-groth16:
$(CIRCOM) $(CIRCOM_OPTS) $(CIRCUITS_DIR)/groth16/circuit.circom -o $(CIRCUITS_DIR)/groth16

circuit-circuit2:
$(CIRCOM) $(CIRCOM_OPTS) $(CIRCUITS_DIR)/circuit2/circuit.circom -o $(CIRCUITS_DIR)/circuit2

circuit-plonk:
$(CIRCOM) $(CIRCOM_OPTS) $(CIRCUITS_DIR)/plonk_circuit/circuit.circom -o $(CIRCUITS_DIR)/plonk_circuit

circuit-fflonk:
$(CIRCOM) $(CIRCOM_OPTS) $(CIRCUITS_DIR)/fflonk/circuit.circom -o $(CIRCUITS_DIR)/fflonk

# ── Verifier template checks ──────────────────────────────────────────

# Dry-run: generate a Groth16 verifier from the template + a zkey and
# print it to stdout. Useful for inspecting the EIP-197 G2 encoding.
#
# Requires: make install (for snarkjs CLI), a compiled circuit, and a
# ptau file (use test/plonk_circuit/powersOfTau15_final.ptau).
#
# make verifier-preview
PTAU_FILE ?= test/plonk_circuit/powersOfTau15_final.ptau
R1CS_FILE ?= test/groth16/circuit.r1cs

verifier-preview:
@snarkjs zkey new $(R1CS_FILE) $(PTAU_FILE) /tmp/verifier_preview.zkey 2>/dev/null
@snarkjs zkey export solidityverifier /tmp/verifier_preview.zkey /tmp/verifier_preview.sol 2>/dev/null
@cat /tmp/verifier_preview.sol
@rm -f /tmp/verifier_preview.zkey /tmp/verifier_preview.sol

# ── Cleanup ───────────────────────────────────────────────────────────

clean:
rm -rf build cache
rm -rf smart_contract_tests/artifacts smart_contract_tests/cache smart_contract_tests/contracts

distclean: clean
rm -rf node_modules smart_contract_tests/node_modules

#
# nix-...:
#
# Use a Nix flake environment to execute the make target, e.g.:
#
# make nix-test
# make nix-test-smart-contracts
# make nix-test-all
#
nix-%:
@if [ -n "$(TARGET)" ]; then \
nix develop .#$(TARGET) $(NIX_OPTS) --command make $*; \
else \
nix develop $(NIX_OPTS) --command make $*; \
fi

#
# Target to allow the printing of 'make' variables, e.g.:
#
# make print-PTAU_FILE
#
print-%:
@echo $* = "'$($*)'"
@echo $*\'s origin is $(origin $*)

FORCE:
57 changes: 57 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,63 @@ await wtnsCalculate(input, wasmFile, wtns, {memorySize: 0});



## Development

To work on snarkjs itself:

```sh
git clone https://github.com/iden3/snarkjs.git
cd snarkjs
npm install
```

### Run tests

**Unit & integration tests** (off-chain proving/verifying):

```sh
npm test # mocha: powers of tau, groth16, plonk, fflonk, polynomials
```

**Smart-contract tests** (on-chain verification via Hardhat):

```sh
cd smart_contract_tests && npm install && npm test
```

### Forge-based on-chain verification (lightweight, auto-skips)

A minimal Foundry-based test that validates exported Groth16 verifiers
against a real EVM precompile engine (revm). No Hardhat, no ethers —
just a single `forge` binary. If Foundry isn't installed the test
prints `SKIP` and exits cleanly.

```sh
make test-forge # 1-input circuit
make test-forge-all # both 1-input and 3-input circuits
```

Install Foundry:

```sh
curl -L https://foundry.paradigm.xyz | bash
foundryup
```

### Nix flake (reproducible dev environment)

A `flake.nix` provides `node`, `circom`, `forge`, `solc`, and all npm
dependencies in a single shell:

```sh
nix develop # enter the dev shell
make nix-test # run unit tests
make nix-test-forge # run forge EVM verification
make nix-test-smart-contracts # run Hardhat on-chain tests
```

All `make nix-<target>` commands delegate to `nix develop --command make <target>`.

## Further resources
- [Announcing the Perpetual Powers of Tau Ceremony to benefit all zk-SNARK projects](https://medium.com/coinmonks/announcing-the-perpetual-powers-of-tau-ceremony-to-benefit-all-zk-snark-projects-c3da86af8377)
- [Scalable Multi-party Computation for zk-SNARK Parameters in
Expand Down
61 changes: 61 additions & 0 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

80 changes: 80 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
{
description = "snarkjs — zkSNARKs implementation in JavaScript (Groth16/PLONK/FFLONK)";

inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05";
flake-utils.url = "github:numtide/flake-utils";
};

outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};

commonInputs = with pkgs; [
# Core tools
cacert
git
gnumake
gnused
bash
bash-completion
which
jq
curl
gh

# Node.js — runtime and build tool
nodejs_22

# circom — compile .circom test circuits → R1CS / WASM
circom

# Foundry — forge (compiler/test), anvil (local node), cast (CLI)
# Provides solc for Hardhat-based smart-contract tests
foundry

# Standalone solc — for IDE/LSP support; Hardhat + Foundry also bundle solc
solc
];
in {
devShells.default = pkgs.mkShell {
buildInputs = commonInputs;
shellHook = ''
export SOLC_PATH="${pkgs.solc}/bin/solc"

echo "snarkjs — zkSNARKs Development Environment"
echo ""
printf " %-12s %s\n" "node" "$(node --version 2>/dev/null)"
printf " %-12s %s\n" "circom" "$(circom --version 2>/dev/null | head -1)"
printf " %-12s %s\n" "forge" "$(forge --version 2>/dev/null | head -1)"
printf " %-12s %s\n" "cast" "$(cast --version 2>/dev/null | head -1)"
printf " %-12s %s\n" "solc" "$(solc --version 2>/dev/null | tail -1)"
printf " %-12s %s\n" "gh" "$(gh --version 2>/dev/null | head -1)"

# Install root npm deps (snarkjs build deps: rollup, mocha, etc.)
if [ ! -d node_modules ] && [ -f package.json ]; then
echo ""
echo "[flake] installing root npm dev deps ..."
npm install --no-audit --no-fund --loglevel=error
fi

# Install smart-contract test deps (hardhat, ethers, chai, etc.)
if [ -f smart_contract_tests/package.json ] && [ ! -d smart_contract_tests/node_modules ]; then
echo ""
echo "[flake] installing smart-contract test npm deps ..."
( cd smart_contract_tests && npm install --no-audit --no-fund --loglevel=error )
fi

# Prepend local node_modules/.bin so snarkjs CLI is on PATH
if [ -x node_modules/.bin/snarkjs ]; then
export PATH="$PWD/node_modules/.bin:$PATH"
printf " %-12s %s\n" "snarkjs" "$(snarkjs --version 2>/dev/null || echo 'installed')"
fi

echo ""
echo "Commands: make all | make test | make test-forge | make nix-test-forge | make build"
'';
};
});
}
6 changes: 6 additions & 0 deletions forge_test/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Generated files from forge verify test
src/
test/
out/
cache/
lib/
8 changes: 8 additions & 0 deletions forge_test/foundry.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"lib/forge-std": {
"tag": {
"name": "v1.16.1",
"rev": "620536fa5277db4e3fd46772d5cbc1ea0696fb43"
}
}
}
13 changes: 13 additions & 0 deletions forge_test/foundry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
test = "test"
solc = "0.8.17"
evm_version = "istanbul"
optimizer = true
optimizer_runs = 999999

# The Groth16 verifier uses inline assembly (bn256Pairing precompile
# at addresses 6, 7, 8). These precompiles are available on all
# post-Byzantium EVMs; Istanbul is a safe default for revm/anvil.
Loading