Skip to content
Merged
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
3 changes: 3 additions & 0 deletions .cursorignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dist/
node_modules/
.env
53 changes: 53 additions & 0 deletions .github/workflows/web-starter-playwright.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: Run web-starter Playwright Tests on PR
on:
pull_request:
paths:
- "web-starter/**"

jobs:
test:
defaults:
run:
working-directory: web-starter

runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

- name: Install Nargo
uses: noir-lang/noirup@v0.1.2
with:
toolchain: stable

- name: Install bb
run: |
curl -L https://raw.githubusercontent.com/AztecProtocol/aztec-packages/refs/heads/master/barretenberg/bbup/install | bash
echo "PATH=$PATH:/home/runner/.bb" >> $GITHUB_ENV

- name: Run bbup
run: |
bbup

- name: Build circuits
run: |
cd circuits && ./build.sh

- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: lts/*

- name: Install JS dependencies
working-directory: web-starter/web
run: |
yarn install

- name: Install Playwright Browsers
working-directory: web-starter/web
run: |
yarn playwright install --with-deps

- name: Run Playwright tests
working-directory: web-starter/web
run: |
yarn test:e2e
10 changes: 10 additions & 0 deletions web-starter/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
cache
out
proofs
broadcast
.env
plonk_vk.sol
web/node_modules
.DS_Store
web/dist
web/test-results
23 changes: 23 additions & 0 deletions web-starter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Introduction

A simple Noir circuit with browser proving with bb.js
Has both webpack and vite bundling.

Tested with Noir 1.0.0-beta.6 and bb 0.84.0

## Setup

```bash
(cd circuits && ./build.sh)
(cd web && yarn)
```

## Run

```bash
# vite
(cd web && yarn vite:dev)

# webpack
(cd web && yarn webpack:dev)
```
7 changes: 7 additions & 0 deletions web-starter/circuits/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name="noir_uh_starter"
type="bin"
authors = ["saleel"]
compiler_version = ">=1.0.0"

[dependencies]
12 changes: 12 additions & 0 deletions web-starter/circuits/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
set -e

echo "Compiling circuit..."
if ! nargo compile; then
echo "Compilation failed. Exiting..."
exit 1
fi

echo "Generating vkey..."
bb write_vk -b ./target/noir_uh_starter.json -o ./target

echo "Done"
5 changes: 5 additions & 0 deletions web-starter/circuits/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

fn main(x: Field, y: pub Field) {
let res = x * 2 + y;
assert(res == 9);
}
1 change: 1 addition & 0 deletions web-starter/circuits/target/noir_uh_starter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"noir_version":"1.0.0-beta.6+e796dfd67726cbc28eb9991782533b211025928d","hash":"2259292795167771491","abi":{"parameters":[{"name":"x","type":{"kind":"field"},"visibility":"private"},{"name":"y","type":{"kind":"field"},"visibility":"public"}],"return_type":null,"error_types":{}},"bytecode":"H4sIAAAAAAAA/62QQQqAMAwErfigpEna5OZXLKb/f4KoFUrxpgPL7mkOG6ab0DIyt15bwzfijy4MnYsgMXuOjoQbRCsqwFKSoqKo7FGJXFmzFctgyORYxcjrhZ6upftiGvbbNw8HOny0w0QBAAA=","debug_symbols":"nZBNCoMwEIXvMussLK1YvUopEuMogSEJY1Io4t07ira66MbV/Lz53sAbocUm9bV1nR+geozQsCWyfU3e6Gi9k+04KdjGOjKirGCnCxU0o4tQuUSk4KUpLUdD0G6pUbOomQJ0rVQx7Czh3E3qR2f/0Vu5svntC+cn6PsJurisdFEe6KdM2lg+ZAUZVNdpNmOrG8I1vy45s4szvsOmbIEH9gbbxDjbLZo8+AA=","file_map":{"50":{"source":"\nfn main(x: Field, y: pub Field) {\n let res = x * 2 + y;\n assert(res == 9);\n}\n","path":"/home/josh/Documents/Github/noir-examples/web-starter/circuits/src/main.nr"}},"names":["main"],"brillig_names":[]}
Binary file added web-starter/circuits/target/vk
Binary file not shown.
17 changes: 17 additions & 0 deletions web-starter/web/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Noir UH Starter</title>
</head>
<body>
<div class="container">
<h1>Noir UH Starter</h1>
<button id="generateProofBtn">Generate Proof</button>
<div style="white-space: pre-wrap" id="result"></div>
</div>
<!-- Needed for vite, but fails in webpack (ignore) -->
<script type="module" src="./main.ts"></script>
</body>
</html>
41 changes: 41 additions & 0 deletions web-starter/web/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { UltraHonkBackend } from "@aztec/bb.js";
import circuit from "../circuits/target/noir_uh_starter.json" with { type: "json" };
import { Noir } from "@noir-lang/noir_js";

function log(message: string) {
console.log(message);
const resultDiv = document.getElementById('result');
if (resultDiv) {
resultDiv.textContent += message + '\n\n';
}
}

async function generateProof(): Promise<void> {
try {
log('Generating proof...');

const noir = new Noir(circuit as any);
const honk = new UltraHonkBackend(circuit.bytecode, { threads: 8 });

const inputs = { x: 3, y: 3 };
const { witness } = await noir.execute(inputs);
const { proof, publicInputs } = await honk.generateProof(witness);

log("Proof: " + proof);
log("Public inputs: " + publicInputs);

const verified = await honk.verifyProof({ proof, publicInputs });
log("Verified: " + verified);

} catch (error) {
log("Error: " + error);
}
}

// Add click event listener when the DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
const button = document.getElementById('generateProofBtn');
if (button) {
button.addEventListener('click', generateProof);
}
});
34 changes: 34 additions & 0 deletions web-starter/web/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "js",
"type": "module",
"dependencies": {
"@aztec/bb.js": "0.84.0",
"@noir-lang/noir_js": "1.0.0-beta.6"
},
"scripts": {
"webpack:dev": "webpack serve",
"webpack:build": "NODE_ENV=production webpack",
"webpack:preview": "webpack serve --mode production",
"vite:dev": "vite",
"vite:build": "vite build",
"vite:serve": "vite serve",
"test:e2e": "playwright test"
},
"devDependencies": {
"@babel/core": "^7.26.7",
"@babel/preset-env": "^7.26.7",
"@playwright/test": "^1.53.0",
"@types/node": "^22.10.1",
"babel-loader": "^9.2.1",
"html-webpack-plugin": "^5.6.3",
"playwright": "^1.53.0",
"ts-loader": "^9.5.2",
"ts-node": "^10.9.2",
"typescript": "^5.8.3",
"vite": "^6.1.0",
"webpack": "^5.97.1",
"webpack-cli": "^6.0.1",
"webpack-dev-server": "^5.2.0"
},
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}
17 changes: 17 additions & 0 deletions web-starter/web/playwright.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// playwright.config.js
// @ts-check
/** @type {import('@playwright/test').PlaywrightTestConfig} */
const config = {
webServer: {
command: 'yarn webpack:dev',
port: 3000,
timeout: 120 * 1000,
reuseExistingServer: !process.env.CI,
},
use: {
baseURL: 'http://localhost:3000',
headless: true,
},
};

module.exports = config;
11 changes: 11 additions & 0 deletions web-starter/web/tests/proof-verification.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { test, expect, Page } from '@playwright/test';

test('proof verification works in the browser', async ({ page }: { page: Page }) => {
await page.goto('/');
await page.click('#generateProofBtn');
// Wait for the result to contain 'Verified:'
await expect(page.locator('#result')).toContainText('Verified:');
// Check that the result contains 'Verified: true' (or similar)
const resultText = await page.locator('#result').innerText();
expect(resultText).toMatch(/Verified:\s*(true|1)/i);
});
27 changes: 27 additions & 0 deletions web-starter/web/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"resolveJsonModule": true,
"esModuleInterop": true,
"allowJs": true,
"strict": true,
"skipLibCheck": true,
"outDir": "./dist",
"baseUrl": "."
},
"include": [
"./**/*.ts",
"./**/*.json"
],
"exclude": [
"node_modules",
"dist"
],
"ts-node": {
"compilerOptions": {
"module": "NodeNext"
}
}
}
14 changes: 14 additions & 0 deletions web-starter/web/vite.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { defineConfig } from 'vite';

export default defineConfig({
optimizeDeps: {
exclude: ['@noir-lang/noirc_abi', '@noir-lang/acvm_js']
},
rollupOptions: {
input: 'index.html',
output: {
dir: 'dist',
format: 'esm'
}
}
});
56 changes: 56 additions & 0 deletions web-starter/web/webpack.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
entry: './main.ts',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
clean: true,
},
performance: {
hints: false,
maxEntrypointSize: 512000,
maxAssetSize: 512000
},
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
use: 'ts-loader'
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
},
resolve: {
extensions: ['.ts', '.js'], // <-- add this so imports work without extensions
},
plugins: [
new HtmlWebpackPlugin({
template: 'index.html'
})
],
devServer: {
static: {
directory: path.join(__dirname, 'dist'),
},
compress: true,
port: 3000,
hot: true,
headers: {
"Cross-Origin-Embedder-Policy": "require-corp",
"Cross-Origin-Opener-Policy": "same-origin"
}
}
};
Loading