Skip to content

chore: generate solidity verifiers for noir circuits [skip-line-limit]#1295

Merged
hmzakhalid merged 6 commits into
mainfrom
chore/1294-noir-verifier
Feb 11, 2026
Merged

chore: generate solidity verifiers for noir circuits [skip-line-limit]#1295
hmzakhalid merged 6 commits into
mainfrom
chore/1294-noir-verifier

Conversation

@hmzakhalid

@hmzakhalid hmzakhalid commented Feb 10, 2026

Copy link
Copy Markdown
Collaborator

Implements automated generation and deployment of Solidity verifier contracts from Noir circuits.

Usage:

pnpm generate:verifiers                    # All circuits
pnpm generate:verifiers --group dkg        # Only DKG circuits
pnpm generate:verifiers --circuit pk       # Specific circuit
pnpm generate:verifiers --clean            # Remove existing verifiers first
pnpm generate:verifiers --dry-run          # Preview only

Summary by CodeRabbit

  • New Features

    • Automated circuit verifier generator with a CLI and integrated deployment flow for circuit verifiers
  • Chores

    • Updated deployed contract records to include new verifier and refund manager entries and wiring
    • Added scripts and npm commands to generate and deploy verifiers
    • Excluded auto-generated verifier contracts from linting
    • Adjusted Solidity compiler optimizer settings
    • Added documentation and shared circuit-group constants for build/generator tooling

@hmzakhalid hmzakhalid linked an issue Feb 10, 2026 that may be closed by this pull request
@vercel

vercel Bot commented Feb 10, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
crisp Ready Ready Preview, Comment Feb 11, 2026 0:29am
enclave-docs Ready Ready Preview, Comment Feb 11, 2026 0:29am

Request Review

@coderabbitai

coderabbitai Bot commented Feb 10, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds end-to-end Noir verifier generation and deployment: a CLI generator for Solidity verifiers, discovery/deploy utilities that link ZKTranscriptLib, integration into enclave deployment flow, package/script/config updates, and updated deployment metadata.

Changes

Cohort / File(s) Summary
Generator CLI
scripts/generate-verifiers.ts
New VerifierGenerator CLI to discover Noir circuits, optionally compile, generate verification keys, run Barretenberg to emit Solidity verifiers, post-process names/headers, and write outputs.
Circuit constants & build
scripts/circuit-constants.ts, scripts/build-circuits.ts
New shared circuit constants/types; build script updated to import common constants/types instead of local definitions.
Verifier deploy utilities
packages/enclave-contracts/scripts/deployAndSave/verifiers.ts, packages/enclave-contracts/scripts/deployVerifiers.ts, packages/enclave-contracts/scripts/index.ts
New utilities to discover verifier contracts, deploy ZKTranscriptLib and verifiers with library linking, persist addresses/blockNumbers, standalone Hardhat deploy script, and re-exported helpers.
Deployment integration
packages/enclave-contracts/scripts/deployEnclave.ts
Invoke verifier deployment during enclave deployment and add a "Circuit Verifiers" summary block in deployment logs.
Ignition module
packages/enclave-contracts/ignition/modules/dkgPkVerifier.ts
New Ignition module exposing DkgPkVerifier contract instance for deployment tooling.
Config & npm scripts
package.json, packages/enclave-contracts/package.json, packages/enclave-contracts/hardhat.config.ts, packages/enclave-contracts/.solhintignore
Added npm scripts generate:verifiers and deploy:verifiers; reduced Solidity optimizer runs (800 → 100); added .solhintignore pattern to exclude generated verifier contracts.
Deployment records
packages/enclave-contracts/deployed_contracts.json
Updated addresses/blockNumbers for many contracts; added E3RefundManager and proxy records; added verifier entries (ZKTranscriptLib, DkgPkVerifier) and updated proxy/init payloads.
Repository scripts docs
scripts/README.md
Documentation added for the verifier generator CLI: usage, options, prerequisites, and examples.
Top-level generator script
scripts/generate-verifiers.ts, scripts/README.md
New generator CLI plus docs; CLI exposed via top-level package script.

Sequence Diagram(s)

sequenceDiagram
    actor Dev as Developer
    participant CLI as generate-verifiers.ts
    participant FS as Filesystem (circuits/bin)
    participant Nargo as nargo
    participant BB as Barretenberg (bb)
    participant Out as contracts/verifier

    Dev->>CLI: run with --group/--circuit
    CLI->>FS: discover circuits & metadata
    alt compile enabled
        CLI->>Nargo: compile circuits
        Nargo-->>CLI: compiled artifacts
    end
    CLI->>BB: generate VKs & Solidity verifiers
    BB-->>CLI: verifier Solidity files
    CLI->>Out: normalize names/headers and write contracts
    CLI-->>Dev: summary of generated verifiers
Loading
sequenceDiagram
    participant Deploy as deployEnclave.ts
    participant VerifierMgr as deployAndSaveAllVerifiers()
    participant Discovery as discoverVerifierContracts()
    participant LibraryDeployer as deployZKTranscriptLib()
    participant Chain as Blockchain
    participant Records as deployed_contracts.json

    Deploy->>VerifierMgr: request verifier deployments
    VerifierMgr->>Discovery: list verifier contracts
    Discovery-->>VerifierMgr: contract names
    loop for each missing verifier
        VerifierMgr->>LibraryDeployer: ensure ZKTranscriptLib deployed
        LibraryDeployer->>Chain: deploy library tx
        Chain-->>Records: store library address/block
        VerifierMgr->>Chain: deploy verifier with linked library
        Chain-->>Records: store verifier address/block
    end
    VerifierMgr-->>Deploy: mapping of verifier name→address
    Deploy->>Deploy: log "Circuit Verifiers" section
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers

  • cedoor
  • ctrlc03
  • 0xjei

Poem

🐰
I hopped through circuits, keys in tow,
I nargo'd, bb'd, then watched them grow,
Solidity flowers from Noir's seed,
Deployed and logged for every need,
Hooray — verifiers ready to go!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly describes the main change: implementing automated generation of Solidity verifiers from Noir circuits, which is accurately reflected in the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/1294-noir-verifier

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@hmzakhalid hmzakhalid self-assigned this Feb 10, 2026
@hmzakhalid hmzakhalid added the chore Something we just need to do for organization label Feb 10, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/enclave-contracts/hardhat.config.ts (1)

176-189: 🛠️ Refactor suggestion | 🟠 Major

Reducing optimizer runs globally affects all contracts, not just verifiers.

Lowering from 800 to 100 runs trades higher runtime gas costs for smaller bytecode — a reasonable tradeoff for large auto-generated verifier contracts that may exceed the 24KB contract size limit. However, this change penalizes all other contracts in the project (e.g., Enclave, BondingRegistry) that benefit from higher optimization runs.

Hardhat supports per-file compiler overrides. Instead of a global reduction, configure overrides at the solidity level to target only the verifier contracts:

Suggested approach
 solidity: {
   compilers: [
     {
       version: "0.8.28",
       settings: {
         optimizer: {
           enabled: true,
-          runs: 100,
+          runs: 800,
         },
         metadata: {
           bytecodeHash: "none",
         },
       },
     },
   ],
+  overrides: {
+    "contracts/verifier/MyVerifier.sol": {
+      settings: {
+        optimizer: {
+          enabled: true,
+          runs: 100,
+        },
+      },
+    },
+  },
 },

Replace "contracts/verifier/MyVerifier.sol" with the specific verifier contract file paths.

🤖 Fix all issues with AI agents
In `@packages/enclave-contracts/deployed_contracts.json`:
- Around line 110-115: Remove the stale top-level "undefined" entry from
deployed_contracts.json and update all deployment scripts (including
verifiers.ts and any script that reads/writes deployed_contracts.json) to stop
using hre.globalOptions.network; instead derive the network via the
signer/provider, e.g. use (await signer.provider?.getNetwork())?.name ??
"localhost" when computing the network key used to store contracts like
PoseidonT3, so future runs write the correct network name rather than
"undefined".

In `@packages/enclave-contracts/ignition/modules/dkgPkVerifier.ts`:
- Around line 8-12: This Ignition module currently defines DkgPkVerifier via
buildModule/DkgPkVerifier and returns { dkgPkVerifier } but is unused and casts
to any; either delete this orphaned module file or implement proper library
linking and typing: import and register the ZKTranscriptLib using
m.library("ZKTranscriptLib", ...) and ensure m.contract("DkgPkVerifier") is
linked to that library just like the scripts/deployAndSave/verifiers.ts flow,
then replace the unsafe "as any" with a concrete module return type matching the
module's contract shape; remove dead exports if you choose deletion.

In `@packages/enclave-contracts/scripts/deployAndSave/verifiers.ts`:
- Around line 59-68: The code uses hre.globalOptions.network to set the chain
name (assigned to variable chain) which can be undefined; update the logic that
sets chain to derive the network name from the signer/provider instead (e.g.,
use the signer or ethers provider getNetwork result and fall back to
'localhost') so readDeploymentArgs and deployment writes use a reliable network
key; change the assignment that creates chain (where hre.globalOptions.network
is read) to use (await signer.provider?.getNetwork())?.name ?? 'localhost' or
equivalent provider.getNetwork() call before calling
readDeploymentArgs(contractName, chain).

In `@scripts/generate-verifiers.ts`:
- Around line 333-351: The CLI parsing loop that handles flags like '--circuit',
'--group', and '--oracle-hash' does not validate the next argument, so args[++i]
may be undefined or another flag; update the for-loop logic to first peek at
args[i+1], ensure it exists and does not start with '-' before consuming it, and
only then assign to options.circuits (push), options.groups (split into
CircuitGroup[]), or options.oracleHash; if the value is missing or invalid,
print a clear error (or call showHelp) and exit with non-zero status to avoid
propagating undefined values into downstream functions like discoverCircuits or
the bb write_vk call.
🧹 Nitpick comments (9)
packages/enclave-contracts/scripts/deployAndSave/verifiers.ts (3)

16-26: discoverVerifierContracts only scans top-level files — non-recursive.

readdirSync without { recursive: true } will miss verifier contracts in subdirectories under contracts/verifier/. If the directory structure is guaranteed to be flat, this is fine, but worth noting for future-proofing.


32-49: linkReferences accessed via as any cast.

The artifact type from Hardhat may not include linkReferences in its type definition, but it is part of the standard Solidity compiler output (and Hardhat artifacts do include it). The as any cast works but silently bypasses type safety. Consider using a type assertion to a more specific interface or checking if the Hardhat v3 artifact type now includes linkReferences.


88-104: Library deployed using short name — could be ambiguous.

Line 90 resolves the library factory using just libName (e.g., "ZKTranscriptLib"), not the fully-qualified name (source:libName). If two different source files define libraries with the same name, this would be ambiguous. Currently this is unlikely but is a latent fragility.

packages/enclave-contracts/scripts/deployEnclave.ts (1)

251-252: Minor indentation mismatch in the deployment log.

verifierLines uses 4-space indentation ( ${name}: ${addr}), but the surrounding template literal context already starts each line at an 4-space indent. The result is that verifier entries will be left-aligned relative to the other entries (e.g., MockFeeToken: ... at column 4 vs verifier names also at column 4), while the Circuit Verifiers: label sits at the same level. This is cosmetically fine but slightly different from what may be intended — if you want sub-items indented under the label, bump verifierLines to 6 or 8 spaces.

scripts/generate-verifiers.ts (5)

344-345: No validation of --group values against known circuit groups.

Passing an invalid group name (e.g., --group foo) silently produces zero results. Consider validating against ALL_GROUPS:

Proposed validation
     } else if (arg === '--group') {
-      options.groups = args[++i]?.split(',') as CircuitGroup[]
+      const val = args[++i]
+      const groups = val?.split(',') ?? []
+      const invalid = groups.filter((g) => !ALL_GROUPS.includes(g as CircuitGroup))
+      if (invalid.length > 0) {
+        console.error(`Error: unknown group(s): ${invalid.join(', ')}. Valid: ${ALL_GROUPS.join(', ')}`)
+        process.exit(1)
+      }
+      options.groups = groups as CircuitGroup[]

207-211: License-header regex is greedy — may consume more than intended.

The pattern (\/\/[^\n]*\n)* after the SPDX match will eat every consecutive //-comment line, not just the license block. If bb ever emits additional // comments (e.g., a version stamp or // Auto-generated) between the license and pragma solidity, those lines will be silently removed. Consider anchoring more tightly, for example by stopping at a blank line or at pragma:

-    solidity = solidity.replace(/\/\/\s*SPDX-License-Identifier:[^\n]*\n(\/\/[^\n]*\n)*/, LICENSE_HEADER)
+    solidity = solidity.replace(/\/\/\s*SPDX-License-Identifier:[^\n]*\n(\/\/[^\n]*\n)*?(?=\n|pragma)/, LICENSE_HEADER)

Low risk with current bb output, but worth hardening.


381-381: require.main === module is a CJS idiom in an ESM-style file.

This works because tsx transpiles to CJS, but it's fragile if the project ever switches to native ESM (e.g., Node's --experimental-strip-types). A more portable guard would be to just call main() unconditionally since this file is only invoked as a script via the generate:verifiers npm script.


254-282: Inconsistent cleanup of bare vk file.

When vk already exists (line 262–264), the file is copied to <pkg>.vk but the original vk is left in place. When vk is freshly generated (line 272–274), the original is removed after copying. If this asymmetry is intentional (preserving a user-supplied vk), a brief comment would help; otherwise, consider unifying the behavior.


238-240: execSync with stdio: 'pipe' swallows stderr on failure.

When nargo compile (or bb) fails, the thrown error's .message only contains the generic "Command failed" text. The actual diagnostic output from the tool is in error.stderr, which is never surfaced to the user. Consider including stderr in the error message:

Proposed improvement
-    execSync('nargo compile', { cwd: circuit.path, stdio: 'pipe' })
+    try {
+      execSync('nargo compile', { cwd: circuit.path, stdio: 'pipe' })
+    } catch (err: any) {
+      const stderr = err.stderr?.toString().trim()
+      throw new Error(`nargo compile failed${stderr ? `:\n${stderr}` : ''}`)
+    }

The same applies to bb write_vk (line 269) and bb write_solidity_verifier (line 194).

Comment thread packages/enclave-contracts/deployed_contracts.json Outdated
Comment thread packages/enclave-contracts/ignition/modules/dkgPkVerifier.ts
Comment thread packages/enclave-contracts/scripts/deployAndSave/verifiers.ts
Comment thread scripts/generate-verifiers.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@packages/enclave-contracts/scripts/deployAndSave/verifiers.ts`:
- Around line 89-91: The deployment uses the short name via
ethers.getContractFactory(libName) which can cause ambiguity for identically
named libraries; change the factory lookup to use the fully qualified name (fqn)
instead of libName (i.e., call ethers.getContractFactory(fqn) when creating
libFactory) and update the console/debug message if desired to reference fqn;
ensure the rest of the code that references libFactory and deployed library
address (variables like libFactory and libName) continues to work with the
FQN-based factory.
- Around line 16-26: The verifier discovery uses process.cwd() which breaks in
monorepos; update discoverVerifierContracts to build verifierDir using __dirname
(or path.resolve(__dirname, "..", "..", "contracts/verifier") as appropriate)
instead of process.cwd(), so the path is resolved relative to the script file;
keep the rest of the logic (fs.existsSync, readdirSync, filter map) unchanged
and ensure verifierDir variable is the only path change.

In `@scripts/generate-verifiers.ts`:
- Around line 267-269: Replace string-interpolated execSync invocations with
execFileSync and pass command + arguments as an array to avoid shell
interpolation: import execFileSync (alongside execSync) and change the call that
currently invokes `execSync(`bb write_vk -b "${jsonFile}" -o
"${targetDir}"${oracleHashFlag}`, { stdio: 'pipe' })` to call
`execFileSync('bb', [ 'write_vk', '-b', jsonFile, '-o', targetDir, /* include
'--oracle_hash' and this.options.oracleHash only if present */ ], { stdio:
'pipe' })`; similarly convert the `bb write_solidity_verifier` and `nargo
compile` calls to use execFileSync with explicit argument arrays so no
user-controlled values (like this.options.oracleHash) are passed into a shell
string.
🧹 Nitpick comments (3)
scripts/generate-verifiers.ts (1)

193-194: execSync calls swallow stderr — failures will be opaque.

All execSync calls use stdio: 'pipe', and on failure the caught error's message rarely includes the process's stderr. Consider capturing stderr and including it in the thrown error for debuggability.

Illustrative approach
-    execSync(`bb write_solidity_verifier -k "${vkPath}" -o "${rawSolPath}"`, { stdio: 'pipe' })
+    try {
+      execSync(`bb write_solidity_verifier -k "${vkPath}" -o "${rawSolPath}"`, { stdio: 'pipe' })
+    } catch (err: any) {
+      throw new Error(`bb write_solidity_verifier failed: ${err.stderr?.toString() ?? err.message}`)
+    }

Same applies to lines 240 and 269.

packages/enclave-contracts/scripts/deployAndSave/verifiers.ts (2)

32-48: Library detection logic looks correct for standard Solidity artifacts.

The unlinked-library placeholder regex and linkReferences extraction are aligned with the standard Hardhat artifact format.

Minor note: (artifact as any).linkReferenceslinkReferences is part of the Hardhat Artifact type, so the as any cast may be unnecessary.


142-149: Redundant network connection — hre.network.connect() called here and again inside each deployAndSaveVerifier call.

deployAndSaveAllVerifiers connects to the network (lines 146-148) solely for logging the chain name, then each deployAndSaveVerifier call reconnects independently. Consider passing the ethers instance and chain as parameters to deployAndSaveVerifier to avoid repeated connections, or at minimum note this is intentional for standalone usage.

Comment thread packages/enclave-contracts/scripts/deployAndSave/verifiers.ts
Comment thread packages/enclave-contracts/scripts/deployAndSave/verifiers.ts Outdated
Comment thread scripts/generate-verifiers.ts
@hmzakhalid hmzakhalid enabled auto-merge (squash) February 10, 2026 22:36
Comment thread packages/enclave-contracts/scripts/deployAndSave/verifiers.ts Outdated
Comment thread scripts/generate-verifiers.ts Outdated
Comment thread scripts/generate-verifiers.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@packages/enclave-contracts/scripts/deployAndSave/verifiers.ts`:
- Around line 86-90: The library FQN currently includes an incorrect "project/"
prefix which prevents Hardhat v3 from matching compiled artifact linkReferences;
update the construction of libraryFQN in verifiers.ts to remove the "project/"
prefix so it becomes `contracts/verifier/${contractName}.sol:ZKTranscriptLib`,
and ensure the libraries object still maps that corrected libraryFQN to
zkTranscriptLibAddress (references: libraryFQN, contractName,
zkTranscriptLibAddress, libraries).

In `@scripts/README.md`:
- Around line 306-318: Update the fenced code block that starts with ``` and
contains "🔮 Generating Solidity verifiers from Noir circuits..." by adding a
language identifier (e.g., change the opening fence from ``` to ```text or
```console) so the block is marked as plain terminal output and satisfies the
MD040 lint rule.
🧹 Nitpick comments (1)
packages/enclave-contracts/scripts/deployAndSave/verifiers.ts (1)

32-59: deployZKTranscriptLib relies on an externally-passed chain while deployAndSaveVerifier derives it internally — consider making this consistent.

deployZKTranscriptLib trusts the caller to pass the correct chain string, while deployAndSaveVerifier (line 77) derives it from the provider. If deployZKTranscriptLib is called standalone with an incorrect chain value, the deployment record will be stored under the wrong network key.

Consider either having deployZKTranscriptLib derive the chain internally (like deployAndSaveVerifier does), or having deployAndSaveVerifier also accept chain as a parameter for consistency.

Comment thread packages/enclave-contracts/scripts/deployAndSave/verifiers.ts
Comment thread scripts/README.md

@cedoor cedoor left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

*We won't need to generate verifiers for wrappers probably.

@ctrlc03 ctrlc03 disabled auto-merge February 11, 2026 08:12
@hmzakhalid hmzakhalid merged commit b4f2f60 into main Feb 11, 2026
26 of 27 checks passed
@github-actions github-actions Bot deleted the chore/1294-noir-verifier branch February 19, 2026 03:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chore Something we just need to do for organization

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Solidity verifier generation and deployment for Noir Circuits

3 participants