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
50 changes: 50 additions & 0 deletions .github/workflows/webgpu.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
on:
pull_request:
paths:
- "backend/accelerated/webgpu/**"
- "backend/groth16/**"
- "backend/plonk/**"
- "internal/generator/backend/**"
- ".github/workflows/webgpu.yml"
name: webgpu

permissions: {}

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
e2e:
# WebGPU needs a GPU-capable browser; the macOS runners expose Metal.
runs-on: macos-latest
permissions:
contents: read
defaults:
run:
working-directory: backend/accelerated/webgpu/web
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: 1.25.x
cache: true
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: backend/accelerated/webgpu/web/package-lock.json
- run: npm ci
- run: npx playwright install chromium
- name: generated shaders and accelerators are up to date
run: |
(cd ../internal/generator && go run .)
git diff --exit-code -- ../shaders ../groth16 ../plonk
- run: npm run build:all
- name: test fixtures
run: |
go run ../internal/testdata/generate --suite api --out tests/fixtures
go run ../internal/testdata/generate --suite groth16 --out tests/fixtures --logs 15 --commitments 1
go run ../internal/testdata/generate --suite plonk --out tests/fixtures --logs 15 --commitments 1
- name: browser tests (API suites + one proof per system and curve)
run: npm run test:e2e
105 changes: 62 additions & 43 deletions backend/accelerated/webgpu/README.md
Original file line number Diff line number Diff line change
@@ -1,61 +1,80 @@
# gnark WebGPU Backend
# gnark WebGPU backend

This package implements gnark prover using WSGL shaders for speeding up most heavy
cryptographic operations. For the prover coordination, we use Go implementation which
is compiled to WASM using Go toolchain. The Go implementation then calls the WSGL
shaders through a Typescrip bridge which in turn executes the WSGL shaders.

It supports Groth16 and PLONK proof systems over BN254, BLS12-377 and BLS12-381.
Experimental browser acceleration of gnark's Groth16 and PLONK provers over
BN254, BLS12-377 and BLS12-381. The prover is gnark's native Go prover compiled
to wasm; its heavy operations (multi-scalar multiplications, FFTs, the PLONK
quotient numerator) are offloaded to WGSL compute shaders driven by a
TypeScript runtime.

## Disclaimer

This is very experimental package. The APIs may change. The backend is not audited.

Currently G2 API tests are failing for BLS12-377 and BLS12-381, but the Groth16/PLONK
prover tests pass.

Due to using Go toolchain for compiling the proving coordinator to WASM, then the
assets are quite big. We have tried TinyGo, but it is incompatible with gnark-crypto
dependency as is.

## Overview

This directory contains gnark's browser WebGPU prover backend:

- `groth16/` contains the Go Groth16 accelerated backend and wasm entrypoints.
- `plonk/` contains the Go PLONK accelerated backend and wasm entrypoints.
- `internal/` contains shared Go bridge and wasm runtime helpers.
- `shaders/` contains the WGSL kernels used by the TypeScript runtime.
- `web/` contains the browser-facing TypeScript API and build configuration.

The Go packages are built only for `GOOS=js GOARCH=wasm`. They call the
TypeScript WebGPU runtime through `syscall/js`, and the TypeScript runtime
loads the Go wasm entrypoints from `web/dist/assets`.
This package is experimental. The APIs may change and the backend is not
audited.

## How it works

The native provers (`backend/groth16`, `backend/plonk`) expose an
`Accelerator` interface on their proving keys: a handful of coarse-grained
hooks (`MultiExp`, `ComputeH` for Groth16; `MultiExp`, `ToCanonical`,
`ComputeNumerator` for PLONK). When no accelerator is attached the prover runs
gnark-crypto on the CPU, so the CPU path is unchanged. This package provides
WebGPU implementations of those hooks:

1. `Prepare(pk)` uploads the proving key bases to the GPU once, through
`syscall/js`, and attaches the accelerator to the key.
2. `groth16.Prove` / `plonk.Prove` then run unchanged; each hook call crosses
the Go to JavaScript boundary with the raw little-endian Montgomery limbs of
gnark-crypto elements (no re-encoding on the Go side), the TypeScript runtime
dispatches the WGSL kernels, and results come back as affine points or
coefficient vectors.

KZG openings go through gnark-crypto's `kzg.OpenWithCommitter` and
`kzg.BatchOpenSinglePointWithCommitter`, so the opening and folding logic is
not duplicated here.

## Layout

- `groth16/`, `plonk/`: `Prepare` / `Release` facades and, per curve, one
generated `accelerator.go` implementing the native prover's `Accelerator`
interface. The `internal/wasmruntime/{native,webgpu}` commands are the wasm
entrypoints loaded by the TypeScript package (native keeps the CPU prover for
comparison).
- `internal/bridge/`: Go client of the JavaScript bridge objects
(`gnarkGroth16WebGPU`, `gnarkPlonkWebGPU`) and the byte protocol.
- `internal/wasmruntime/`: JavaScript-facing runtime (read keys and
constraint systems, prove, verify) shared by the four entrypoints.
- `internal/generator/`: bavard generator. Produces the per-curve Go
accelerators (`templates/go`), the per-curve WGSL shaders (`templates/wgsl`,
with all field constants computed from gnark-crypto) and the Go test-vector
builders. Run `go run .` in that directory after editing a template.
- `shaders/`: WGSL kernels. `shaders/curves/*` are generated, `shaders/common/*`
are hand-written and curve-agnostic (MSM bucket sort, Pippenger stages).
- `web/`: TypeScript runtime, browser test pages, the npm build and
`scripts/e2e.mjs`, which runs the test pages headlessly with Playwright.

The Go packages build only for `GOOS=js GOARCH=wasm`.

## Build

Install TypeScript dependencies from `web/package-lock.json`:

```sh
cd backend/accelerated/webgpu/web
npm ci
npm run build:all # lint, shaders bundle, TypeScript, Go wasm assets
```

Build the TypeScript package, bundled shaders, and Go wasm assets:
Narrower targets: `npm run build`, `build:shaders`, `build:wasm`,
`build:wasm:groth16`, `build:wasm:plonk`, `lint`.

```sh
npm run build:all
```
## Test

Useful narrower targets:
Test fixtures for the browser pages are produced with
`npm run build:test-fixtures:<suite>` (api, groth16, plonk). The pages can be
served from `web/` and opened at `tests/index.html`, or run headlessly:

```sh
npm run build
npm run build:shaders
npm run build:wasm
npm run build:wasm:groth16
npm run build:wasm:plonk
npm run lint
npm run test:e2e # API suites + one verified proof per system and curve
npm run bench:e2e # prover benchmark matrix (2^15 and 2^18 fixtures)
```

`npm run build:shaders` generates `web/src/curvegpu/shader_bundle.generated.ts` from `shaders/`.
Set `PW_CHANNEL=chrome` to use the system Chrome instead of Playwright's
Chromium. `.github/workflows/webgpu.yml` runs `test:e2e` on pull requests.
170 changes: 170 additions & 0 deletions backend/accelerated/webgpu/groth16/bls12-377/accelerator.go

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

Loading
Loading