npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

groth16-webgpu

v0.1.0

Published

Groth16 (BN254) zkSNARK prover with FFT + MSM in pure WGSL/WebGPU. Zero production dependencies. Consumes snarkjs .zkey + .wtns, emits proofs that snarkjs.groth16.verify accepts.

Readme

groth16-webgpu

Groth16 (BN254) zkSNARK prover with FFT + MSM in pure WGSL/WebGPU. Zero production dependencies. Consumes snarkjs .zkey + .wtns files and emits proofs that snarkjs.groth16.verify accepts.

~2.3× faster than rapidsnark C++ on RSA-2048 (149k constraints): ~300 ms vs ~676 ms.

Features

  • Pure GPU compute — FFT and MSM pipelines run entirely on the GPU via WebGPU/WGSL.
  • Zero production deps — no snarkjs, no bigint libraries at runtime.
  • snarkjs-compatible — consumes standard .zkey and .wtns files, produces proofs that pass snarkjs.groth16.verify.
  • Hot-path optimizationnew() does all one-time work (shader compilation, base upload, scratch allocation); prove() is a minimal-latency hot path.
  • Five MSM jobs batched into a single GPU submission (G1-A, G1-B1, G2-B2, G1-C, G1-H) with concurrent execution on capable GPUs.
  • Sorted-bucket Pippenger for all MSMs, with parallel ones-reduction for witness-skewed scalars.

API

import { Groth16Prover, prove } from "groth16-webgpu";

Groth16Prover (reusable, recommended)

// ── Full initialization (one-time) ──
const prover = await Groth16Prover.new(zkeyBytes: Uint8Array);

// ── Hot-path proving (per-proof) ──
const result: ProveResult = await prover.prove(wtnsBytes: Uint8Array, opts?: ProveOptions);

// ── Cleanup ──
prover.dispose();

Groth16Prover.new(zkeyBytes)

Parses the .zkey, acquires the WebGPU device, compiles all shaders, uploads MSM base tables and FFT twiddles, builds QAP CSR tables, and pre-allocates all scratch buffers.

Returns a Groth16Prover instance with an initProfile property containing timing breakdown:

interface InitProfile {
  zkey_parse: number;     // Parse the .zkey on the host
  device_init: number;    // Acquire WebGPU device
  shader_compile: number; // Compile shaders + build pipelines
  upload_bases: number;   // Upload MSM base tables
  upload_twiddles: number;// Upload FFT twiddles
  build_csr: number;      // Build QAP CSR tables
  prepare_msm: number;    // Pre-allocate MSM scratch
  total: number;          // Total init time
}

prover.prove(wtnsBytes, opts?)

Hot path. Parses the witness, DMAs it to the pre-allocated GPU buffers, runs BuildABC → Coset FFT chain → Batched MSM → host assembly.

Options:

interface ProveOptions {
  r?: bigint;      // Optional blinding factor (random by default)
  s?: bigint;      // Optional blinding factor (random by default)
  verbose?: boolean; // Print detailed profiling and debug output
}

Returns:

interface ProveResult {
  proof: ProofPoints;
  publicSignals: string[];
  profile: ProveProfile;
}

interface ProofPoints {
  pi_a: [string, string];
  pi_b: [[string, string], [string, string]];
  pi_c: [string, string];
  protocol: "groth16";
  curve: "bn128";
}

interface ProveProfile {
  io_parsing: number;
  gpu_prep: number;
  build_abc: number;
  fft: number;
  msm: MsmStageProfile;
  assembly: number;
}

The proof object is in the exact format expected by snarkjs.groth16.verify.

prover.dispose()

Releases all GPU buffers (bases, twiddles, CSR tables, scratch, pipelines). The prover must not be used after disposal.

prove() (one-shot convenience)

const result = await prove(zkeyBytes, wtnsBytes, opts?);

Creates a temporary Groth16Prover, runs one proof, disposes. Convenient for one-off use but incurs init cost every call.

Quick Start

import { Groth16Prover } from "groth16-webgpu";
import * as snarkjs from "snarkjs";

const zkeyBytes = await Bun.file("circuit.zkey").arrayBuffer();
const wtnsBytes = await Bun.file("circuit.wtns").arrayBuffer();
const vkey = JSON.parse(await Bun.file("vkey.json").text());

// Initialize (one-time: shader compile, base upload, scratch alloc)
const prover = await Groth16Prover.new(new Uint8Array(zkeyBytes));

// Prove (hot path)
const { proof, publicSignals, profile } = await prover.prove(new Uint8Array(wtnsBytes));
console.log(`Proved in ${profile.total.toFixed(1)} ms`);

// Verify (via snarkjs)
const verified = await snarkjs.groth16.verify(vkey, publicSignals, proof);
console.log("Verified:", verified);

prover.dispose();

Requirements

  • Browser: Chrome 113+ or any browser with WebGPU support (navigator.gpu required).
  • Node/Bun: Not directly supported (WebGPU not available in Node). For local benchmarks, use the bench-local.ts CPU comparison script or the browser-based demo.
  • Environment: macOS (Metal), Windows (D3D12), or Linux (Vulkan) with a WebGPU-capable GPU.

Commands (from packages/groth16-webgpu)

| Command | Description | |---|---| | bun test | Pure-TS suite (field/FFT/curve/prove-vs-golden), no GPU | | bun run test:wgsl | Headless WGSL unit tests | | bun run test:browser | Small circuit e2e (WebGPU + snarkjs verify) | | bun run bench:rsa | RSA-2048 benchmark | | bun run build:shaders | Regenerate src/gpu/shaders.ts from shaders/*.wesl | | bun run gen:rsa | Regenerate RSA fixture |

Pipeline

.zkey ──► parse ──► BuildABC (QAP) ──► Coset FFT chain ──► 5× MSM (G1+G2) ──► Host assembly ──► Proof
.wtns ──►             ↑                              ↑
               (GPU: CSR tables)            (GPU: twiddle factors)

Internally mirrors the snarkjs Groth16 prover pipeline exactly. A pure-TS bigint reference prover (src/reference/) serves as the correctness oracle and matches snarkjs bit-for-bit; golden vectors in fixtures/golden.json.

Benchmark (RSA-2048, 149k constraints)

| Stage | Time (ms) | |---|---| | IO & Parser | ~0.0 | | GPU Buffer Prep | ~5 | | BuildABC (QAP) | ~0.2 | | Coset FFT Chain | ~1.2 | | MSM (4× G1 + 1× G2) | ~260 | | Host Assembly | ~3 | | Total | ~270 |

Measured on MacBook Pro (Apple Silicon, Chrome/WebGPU, warm, best-of-run). ~2.5× faster than rapidsnark C++ (~676 ms).

License

MIT