Skip to content

Developer onboarding: make targets, optional Nix dev shell, and a Foundry on-chain verifier test - #632

Open
pjkundert wants to merge 3 commits into
iden3:masterfrom
pjkundert:feature/nix-forge-harness
Open

Developer onboarding: make targets, optional Nix dev shell, and a Foundry on-chain verifier test#632
pjkundert wants to merge 3 commits into
iden3:masterfrom
pjkundert:feature/nix-forge-harness

Conversation

@pjkundert

Copy link
Copy Markdown

What this adds

Three additive pieces aimed at one thing: letting a new developer or tester go from git clone to running every test layer with single commands, instead of discovering the setup sequence by reading package.json and smart_contract_tests/ first.

1. A Makefile with one command per test layer

make install                # npm install here and in smart_contract_tests/
make test                   # the mocha suite (exactly what CI runs)
make test-smart-contracts   # the Hardhat on-chain suite
make test-forge             # the new Foundry on-chain test (below)
make test-all               # all three
make test-file FILE=... | test-grep GREP=...
make circuits               # recompile bundled test circuits after edits

2. An optional Nix dev shell (flake.nix)

For anyone with Nix installed, setup disappears entirely: any target prefixed nix- runs inside a shell supplying node, circom, foundry, and a pinned solc (so forge never downloads a compiler):

make nix-test
make nix-test-smart-contracts
make nix-test-forge
make nix-test-all

Non-Nix users are unaffected — the plain targets work with whatever toolchain is on PATH.

3. A self-contained Foundry harness (make test-forge)

Proves a bundled test circuit, exports the standard Solidity verifier, and runs verifyProof on a real EVM via forge test — including a negative test that an aliased public input is rejected. The generated test packs the proof's _pB with the same EIP-197 coordinate swap snarkjs zkey export soliditycalldata performs. It complements the Hardhat suite from the Foundry side: revm enforces the EIP-197 point encodings strictly, so this layer exercises the calldata path that off-chain groth16 verify never crosses.

Self-contained by design: no submodules, no forge-std, no network access, and it auto-skips with exit 0 when forge is not installed, so no existing workflow or CI job is affected.

What this does not change

No library code, no templates, no existing tests. npm test and the Hardhat suite are untouched — the Makefile only wraps them.

Tested

On macOS arm64, through the flake from a clean checkout:

  • make nix-test → 49 passing (the same npm test CI runs)
  • make nix-test-smart-contracts → 7 passing
  • make nix-test-forge → 2/2, make nix-test-forge-all → 2/2 + 2/2 (test/groth16 and test/circuit2)

Independent of #631 (docs); the two share no files.

Add a lightweight Foundry harness that exercises an exported Solidity
verifier on a real EVM (forge's built-in revm):

    make test-forge        # prove + verify test/groth16 on-chain
    make test-forge-all    # also test/circuit2

scripts/forge_verify_test.sh generates a zkey and proof from a bundled
test circuit, exports the verifier with 'snarkjs zkey export
solidityverifier', writes a forge test with the proof embedded, and
runs it.  The generated test packs verifyProof()'s _pB argument in
EIP-197 order ([x_im, x_re, y_im, y_re]) -- the same caller-side
coordinate swap that 'snarkjs zkey export soliditycalldata' performs --
so it exercises the exported verifier and the documented calldata
convention together, and it also checks that an aliased
(field-modulus-wrapped) public input is rejected.

The harness is self-contained: no submodules, no forge-std, and no
network access -- the generated test's only import is the verifier
itself, and forge treats any test_* function that reverts as a failure,
so plain require() suffices.  If forge is not installed the target
prints SKIP and exits 0, so it can run in CI without making Foundry a
hard dependency.
flake.nix provides node, circom, and Foundry, plus a Nix-pinned solc
wired to forge via FOUNDRY_SOLC, so 'make test-forge' compiles the
exported verifier without downloading a compiler.  The shell hook
prints tool versions, installs the npm dev dependencies on first
entry, and lists the test entry points (npm test, make test-forge,
make test-forge-all, smart_contract_tests).

README: note that 'nix develop' supplies the toolchain for the forge
targets.
Getting this repo's three test layers running -- Node/mocha unit tests,
Hardhat on-chain tests, and the Foundry harness -- takes several tools and
several working directories.  This makes each layer a single command and
documents them in one place:

  make install | build | test | test-smart-contracts | test-forge | test-all
  make test-file FILE=... | test-grep GREP=...
  make circuits | verifier-preview | clean | distclean

and, with Nix installed, removes the setup entirely: any target prefixed
nix- runs inside the flake's dev shell, which supplies node, circom, forge
and a pinned solc (so forge never downloads a compiler):

  make nix-test
  make nix-test-smart-contracts
  make nix-test-forge
  make nix-test-all

The README's Foundry section grows into "Building and testing with make
(and Nix)" with a target table, keeping the forge harness details as a
subsection.

Verified through the flake on a clean checkout: nix-test-forge 2/2,
nix-test-smart-contracts 7 passing, nix-test runs the full mocha suite.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant