diff --git a/.github/workflows/web-starter-playwright.yml b/.github/workflows/web-starter-playwright.yml index 673977f5..c626955b 100644 --- a/.github/workflows/web-starter-playwright.yml +++ b/.github/workflows/web-starter-playwright.yml @@ -19,7 +19,7 @@ jobs: - name: Install Nargo uses: noir-lang/noirup@v0.1.2 with: - toolchain: stable + toolchain: 1.0.0-beta.11 - name: Install bb run: | @@ -81,6 +81,9 @@ jobs: - name: Run Playwright tests (next) working-directory: web-starter/web/nextjs + env: + CI: true + NODE_OPTIONS: "--max-old-space-size=4096" run: | yarn test:e2e diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..e9450430 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,262 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Overview + +This is a reference repository of examples for writing zero-knowledge circuits and applications with [Noir](https://noir-lang.org/). Each subdirectory is a standalone example project demonstrating different Noir use cases and integration patterns. + +## Prerequisites + +- **Noir (nargo)**: Install via `noirup` - [installation instructions](https://noir-lang.org/docs/getting_started/installation) +- **Barretenberg (bb)**: Install via `bbup` - the proving backend for Noir circuits +- **Node.js/Yarn**: For JavaScript/TypeScript examples +- **Foundry**: Required for Solidity verification examples (`curl -L https://foundry.paradigm.xyz | bash`) + +Quick setup for all examples: +```bash +chmod +x ./scripts/setup-all.sh +./scripts/setup-all.sh +``` + +## Core Development Commands + +### Noir Circuit Development + +```bash +# Compile a Noir circuit +nargo compile + +# Run tests in a Noir circuit +nargo test + +# Execute circuit to generate witness +nargo execute + +# Generate verifier contract (for Solidity integration) +nargo codegen-verifier + +# Prove with bb CLI +bb prove -b ./target/.json -w target/.gz -o ./target --oracle_hash keccak + +# Generate verification key +bb write_vk --oracle_hash keccak -b ./target/.json -o ./target + +# Generate Solidity verifier +bb write_solidity_verifier -k ./target/vk -o /Verifier.sol +``` + +### JavaScript/TypeScript Proof Generation + +Most examples use `yarn` for package management: +```bash +# Install dependencies +yarn install + +# Generate proofs (common script name) +yarn generate-proof + +# Run tests +yarn test +``` + +### Foundry (Solidity Examples) + +```bash +# Test Solidity contracts with proof verification +forge test --optimize --optimizer-runs 5000 --gas-report -vvv + +# Build contracts +forge build + +# Deploy (example from solidity-example) +forge script script/Deploy.s.sol:DeployScript --rpc-url --broadcast --legacy +``` + +## Project Structure + +### Main Examples + +- **`solidity-example/`** - End-to-end example of generating Noir proofs and verifying them on-chain with Solidity verifiers + - `/circuits` - Noir circuit source + - `/js` - JavaScript proof generation using `@noir-lang/noir_js` and `@aztec/bb.js` + - `/contract` - Foundry project with Solidity verifier contracts + - Build: `(cd circuits && ./build.sh)` compiles circuit and generates Solidity verifier + +- **`recursion/`** - Demonstrates recursive proof generation where one circuit verifies another circuit's proof + - `/circuits/inner` - Inner circuit that gets proven first + - `/circuits/recursive` - Outer circuit that verifies the inner proof + - `/js` - TypeScript code for generating both proofs + - Build: `(cd circuits && ./build.sh)` compiles both circuits + +- **`web-starter/`** - Browser-based proof generation examples + - `/circuits` - Simple Noir circuit + - `/web/vite` - Vite bundler setup + - `/web/webpack` - Webpack bundler setup + - `/web/nextjs` - Next.js integration + - Each web framework requires: circuit compilation (`./circuits/build.sh`), then framework-specific setup + +- **`bignum_example/`** - Demonstrates `noir-bignum` library for BLS12-381 field arithmetic + - Minimal example focusing only on Noir circuit usage + - Run: `nargo execute` in circuits directory + +- **`lib_examples/`** - Examples using Noir libraries + - `base64_example/` - Base64 encoding/decoding using `noir-base64` library + - Uses workspace structure with shared Nargo.toml + +- **`stealthdrop/`** - Complex example using ecrecover, Merkle trees, and PLUME signatures + - Demonstrates integration of multiple cryptographic libraries + - Uses `noir_bigcurve`, `ecrecover`, and custom merkle tree implementations + +- **`noir_by_example/`** - Small focused examples of Noir language features + - `loops/` - Loop constructs in Noir + - `generic_traits/` - Generic types and traits + - `simple_macros/` - Macro usage + - Each has both `/noir` (circuit) and `/rust` (host code) directories + +## Architecture Patterns + +### Noir Circuit Structure + +Noir circuits are defined in `src/main.nr` files within a Nargo project: +- `Nargo.toml` - Project configuration (similar to Cargo.toml) +- `Prover.toml` - Input values for circuit execution +- `src/main.nr` - Main circuit logic +- Compiled artifacts go to `target/` directory + +Circuit main function signature: +```noir +fn main(private_input: Field, public_output: pub Field) { + // Circuit constraints +} +``` + +### JavaScript Proof Generation Pattern + +Common pattern across examples using `@noir-lang/noir_js` and `@aztec/bb.js`: +1. Import compiled circuit artifacts from `target/` directory +2. Initialize Noir program with artifacts +3. Generate witness from inputs +4. Use Barretenberg backend to generate proof +5. (Optional) Verify proof or pass to Solidity verifier + +### Solidity Verification Pattern + +1. Generate Solidity verifier using `bb write_solidity_verifier` +2. Deploy verifier contract to EVM chain +3. Format proof and public inputs for Solidity +4. Call verifier contract's `verify()` function + +## Version Compatibility + +Different examples may use different Noir/bb versions: +- `solidity-example/`: Noir 1.0.0-beta.8, bb 0.87.0 +- `recursion/`: Noir 1.0.0-beta.6, bb 0.84.0 +- `web-starter/`: Noir 1.0.0-beta.11, bb 0.87.0 + +Check each project's README for specific version requirements. Version mismatches between nargo and bb can cause compilation or proof generation issues. + +## Testing Strategy + +- **Noir unit tests**: Use `#[test]` annotations in `.nr` files, run with `nargo test` +- **JavaScript tests**: Usually TypeScript files with test runner (Node.js `--test` or similar) +- **Solidity tests**: Foundry tests in `/test` directories +- **E2E tests**: Some examples have Playwright tests for browser proving + +## Common Build Scripts + +Most circuit directories contain a `build.sh` script that: +1. Compiles the Noir circuit with `nargo compile` +2. Generates verification key with `bb write_vk` +3. (For Solidity examples) Generates Solidity verifier contract + +Always run the build script after modifying circuits. + +## Contributing Notes + +When adding new examples (per CONTRIBUTING.md): +1. Include Noir circuits +2. Provide execution context (JS/browser/Solidity) +3. Write comprehensive README with setup/run instructions +4. Add automated tests and CI workflow in `.github/workflows/` + +Original authors/maintainers for questions: @critesjosh, @signorecello + +## PR Review Guidelines + +When reviewing pull requests that add new examples, ensure the following requirements are met: + +### Example Quality +- **Simplicity**: New examples should be simple and easy to understand. They should focus on demonstrating a specific concept or integration pattern without unnecessary complexity. +- **Clear Purpose**: The example should have a well-defined educational goal that's distinct from existing examples. + +### README Requirements +Every new example MUST include a comprehensive README.md that explains: + +1. **What the example is**: Clear description of what the example demonstrates and why it's useful +2. **What's included**: Overview of the folder structure and key files + - Example: "`/circuits` - Noir circuit source, `/js` - Proof generation code, `/contract` - Solidity verifier" +3. **How to run**: Step-by-step instructions including: + - Prerequisites and installation steps + - Build commands + - Execution commands + - Expected output + - Common troubleshooting tips + +### CI/CD Requirements +New examples MUST include a GitHub Actions workflow in `.github/workflows/` that: + +1. **Runs on PRs**: Tests should run when the example's files are modified + ```yaml + on: + pull_request: + paths: + - "example-name/**" + ``` + +2. **Runs nightly**: Include a scheduled run at 2 AM UTC + ```yaml + schedule: + - cron: "0 2 * * *" + ``` + +3. **Includes workflow_dispatch**: Allow manual triggering + ```yaml + workflow_dispatch: + ``` + +4. **Notifies on failure**: Must create an issue when nightly tests fail + ```yaml + permissions: + issues: write + + - name: Create issue on failure (nightly) + if: failure() && github.event_name == 'schedule' + uses: actions/github-script@v6 + with: + script: | + github.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: '[Nightly] Example-name workflow failed', + body: `The nightly example-name workflow failed. Please investigate.\n\n/cc @noir-lang/developerrelations`, + labels: ['nightly', 'bug'] + }) + ``` + +5. **Comprehensive testing**: Should test the complete workflow: + - Compile Noir circuits (`nargo compile`) + - Run Noir unit tests (`nargo test`) + - Execute proof generation + - (If applicable) Verify proofs on-chain or in JavaScript + +### Review Checklist +- [ ] Example is simple and focused on one concept +- [ ] README explains what, why, and how +- [ ] README includes folder structure overview +- [ ] README has complete setup and run instructions +- [ ] CI workflow runs on PRs with path filter +- [ ] CI workflow runs nightly (cron schedule) +- [ ] CI workflow creates issues on nightly failures +- [ ] Tests cover the complete example workflow +- [ ] Example works with current stable Noir/bb versions (or documents version requirements) diff --git a/scripts/setup-all.sh b/scripts/setup-all.sh index 54100d12..a3951df5 100644 --- a/scripts/setup-all.sh +++ b/scripts/setup-all.sh @@ -1,8 +1,11 @@ #!/usr/bin/env bash -# This script was created to make it easy to set up the environment for OpenAI Codex. -# It automates the installation and setup of all necessary dependencies for the -# noir-examples repository, including Noir, Barretenberg, Node.js packages, and Rust projects. +# This script automates the installation and setup of all necessary dependencies +# for the noir-examples repository, including Noir, Barretenberg, Node.js packages, +# and Rust projects. +# +# Usage: ./scripts/setup-all.sh +# Make executable first: chmod +x ./scripts/setup-all.sh set -euo pipefail @@ -17,30 +20,49 @@ curl -sSL https://raw.githubusercontent.com/AztecProtocol/aztec-packages/refs/he export PATH="$HOME/.bbup/bin:$PATH" bbup -echo "\n--- Compiling all Noir circuits ---" -find . -name 'Nargo.toml' | while read -r nargo_toml; do +echo "" +echo "--- Compiling all Noir circuits ---" +find . -name 'Nargo.toml' -not -path "*/node_modules/*" -not -path "*/target/*" | while read -r nargo_toml; do dir=$(dirname "$nargo_toml") - echo "Compiling Noir circuit in $dir" - (cd "$dir" && nargo compile || echo "Failed to compile in $dir") + # Skip workspace members - they'll be compiled by workspace root + if grep -q "^\[workspace\]" "$nargo_toml" 2>/dev/null; then + echo "Compiling Noir workspace in $dir" + (cd "$dir" && nargo compile || echo "Failed to compile in $dir") + elif ! grep -q "members" "$(dirname "$dir")/Nargo.toml" 2>/dev/null; then + # Only compile if not a workspace member + echo "Compiling Noir circuit in $dir" + (cd "$dir" && nargo compile || echo "Failed to compile in $dir") + fi done -echo "\n--- Installing Node.js dependencies ---" -find . -name 'package.json' | while read -r pkg; do +echo "" +echo "--- Installing Node.js dependencies ---" +find . -name 'package.json' \ + -not -path "*/node_modules/*" \ + -not -path "*/.next/*" \ + -not -path "*/dist/*" \ + -not -path "*/target/*" | while read -r pkg; do dir=$(dirname "$pkg") - if [ -f "$dir/package-lock.json" ] || [ -f "$dir/yarn.lock" ]; then - echo "Installing Node.js deps in $dir" - (cd "$dir" && (npm install || yarn install) || echo "Failed to install Node.js deps in $dir") + echo "Installing Node.js deps in $dir" + if [ -f "$dir/yarn.lock" ]; then + (cd "$dir" && yarn install || echo "Failed to install Node.js deps in $dir") + elif [ -f "$dir/package-lock.json" ]; then + (cd "$dir" && npm install || echo "Failed to install Node.js deps in $dir") else - echo "Installing Node.js deps in $dir" + # Default to npm if no lockfile exists (cd "$dir" && npm install || echo "Failed to install Node.js deps in $dir") fi done -echo "\n--- Installing Rust dependencies ---" -find . -name 'Cargo.toml' | while read -r cargo; do +echo "" +echo "--- Installing Rust dependencies ---" +find . -name 'Cargo.toml' \ + -not -path "*/node_modules/*" \ + -not -path "*/target/*" | while read -r cargo; do dir=$(dirname "$cargo") echo "Building Rust project in $dir" (cd "$dir" && cargo build || echo "Failed to build Rust project in $dir") done -echo "\nAll done!" \ No newline at end of file +echo "" +echo "All done!" diff --git a/web-starter/web/nextjs/playwright.config.cjs b/web-starter/web/nextjs/playwright.config.cjs index 4559b398..b6f3383a 100644 --- a/web-starter/web/nextjs/playwright.config.cjs +++ b/web-starter/web/nextjs/playwright.config.cjs @@ -5,17 +5,22 @@ const config = { webServer: { command: 'yarn build && yarn start', port: 3000, - timeout: 120 * 1000, - reuseExistingServer: !process.env.CI, + timeout: 180 * 1000, // Increased to 3 minutes for CI }, use: { baseURL: 'http://localhost:3000', headless: true, }, + // Global test timeout for proof generation + timeout: 300000, // 5 minutes + expect: { + timeout: 180 * 1000, // 3 minutes for assertions + }, projects: [ { name: 'chromium', use: { browserName: 'chromium' } }, { name: 'firefox', use: { browserName: 'firefox' } }, - { name: 'webkit', use: { browserName: 'webkit' } }, + // WebKit skipped in CI due to high memory usage during proof generation + ...(process.env.CI ? [] : /** @type {any} */ ([{ name: 'webkit', use: { browserName: 'webkit' } }])), ], }; diff --git a/web-starter/web/nextjs/tests/proof-verification.spec.ts b/web-starter/web/nextjs/tests/proof-verification.spec.ts index ad23171e..6cd88318 100644 --- a/web-starter/web/nextjs/tests/proof-verification.spec.ts +++ b/web-starter/web/nextjs/tests/proof-verification.spec.ts @@ -2,17 +2,25 @@ import { test, expect, Page } from '@playwright/test'; // Next.js version test('proof verification works in the browser', async ({ page }: { page: Page }) => { + await page.goto('/'); + + // Wait for the page to be fully loaded + await page.waitForSelector('#generateProofBtn'); + await page.click('#generateProofBtn'); - // Wait for the result to contain 'Verified:' with increased timeout + + // Wait for proof generation to start + await expect(page.locator('#result')).toContainText('Generating proof...', { timeout: 10000 }); + + // Wait for the result to contain 'Verified:' with 5 minute timeout let resultText = ''; try { - await expect(page.locator('#result')).toContainText('Verified:', { timeout: 30000 }); + await expect(page.locator('#result')).toContainText('Verified:', { timeout: 300000 }); resultText = await page.locator('#result').innerText(); } catch (e) { // Debug: print the current contents of #result if the check fails resultText = await page.locator('#result').innerText(); - console.log('DEBUG: #result contents at failure:', resultText); throw e; } // Check that the result contains 'Verified: true' (or similar)