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

@blueshift-gg/xark-wasm

v0.2.0

Published

Generate and verify **Groth16 (BN254) zero knowledge proofs** in the browser or other JavaScript environments with [xark](https://github.com/blueshift-gg/xark).

Downloads

198

Readme

xark-wasm

Generate and verify Groth16 (BN254) zero knowledge proofs in the browser or other JavaScript environments with xark.

import init, { prove, verify } from "@blueshift-gg/xark-wasm";

await init();

const [circuit, pk, vk] = await Promise.all([
  fetch("/circuit/circuit.xbc").then((r) => r.arrayBuffer()),
  fetch("/circuit/pk.bin").then((r) => r.arrayBuffer()),
  fetch("/circuit/vk.bin").then((r) => r.arrayBuffer()),
]);

const { proof, publicInputs } = prove(circuit, pk, { secret: "3", result: "27" });
verify(vk, proof, publicInputs); // true

Runs anywhere with Web Crypto: browsers, Node 20+, Cloudflare Workers, Vercel Edge, Deno. The circuit, proving/verifying keys, proof, and public inputs are all binary — only the witness inputs (a tiny name → value map) cross the boundary as a plain object. Every binary argument accepts a Uint8Array or an ArrayBuffer, so the result of response.arrayBuffer() (or a Node Buffer) can be passed straight in — no new Uint8Array(...) wrap.

Producing circuit artifacts

Before proving, you need the circuit bytecode and proving/verifying keys. Produce them with the xark CLI:

xark build    # → target/xark/<name>/circuit.xbc   (binary, self-contained)
xark setup    # → target/xark/<name>/{pk.bin, vk.bin}

circuit.xbc is the single self-contained build artifact: it encodes both the solver view (witness generation) and the backend view (the minimized R1CS the proving key is keyed to)

Usage

Browser

import init, { prove, verify } from "@blueshift-gg/xark-wasm";

await init();

const [circuit, pk, vk] = await Promise.all([
  fetch("/circuit/circuit.xbc").then((r) => r.arrayBuffer()),
  fetch("/circuit/pk.bin").then((r) => r.arrayBuffer()),
  fetch("/circuit/vk.bin").then((r) => r.arrayBuffer()),
]);

const { proof, publicInputs } = prove(circuit, pk, { secret: "3", result: "27" });

console.log(verify(vk, proof, publicInputs)); // true

Node.js

The Node build does not require a separate init() step.

import { readFileSync } from "node:fs";
import { prove, verify } from "@blueshift-gg/xark-wasm";

// `readFileSync` returns a Buffer, which is a Uint8Array — pass it straight in.
const xbc = readFileSync("examples/cube/target/xark/cube/circuit.xbc");
const pk  = readFileSync("examples/cube/target/xark/cube/pk.bin");
const vk  = readFileSync("examples/cube/target/xark/cube/vk.bin");

const { proof, publicInputs } = prove(xbc, pk, { secret: "3", result: "27" });

console.log(verify(vk, proof, publicInputs)); // true

Performance optimization (preloading)

prove re-expands the .xbc and re-minimizes the R1CS on every call. For repeated proofs against the same circuit + key, parse them once with preload and call prove_preloaded:

preload(circuit, pk);
const a = prove_preloaded({ secret: "3", result: "27" });
const b = prove_preloaded({ secret: "2", result: "8" });

API

prove(circuitXbc, pkBytes, inputs)

Generates a Groth16 proof entirely in memory.

| argument | type | description | |--------------|-------------------------------|-------------------------------------------------------| | circuitXbc | Uint8Array | ArrayBuffer | circuit.xbc (binary, self-contained build artifact) | | pkBytes | Uint8Array | ArrayBuffer | Proving key (pk.bin, binary) | | inputs | object | Witness values as { name: "value" } |

Returns a ProofBundle:

| field | type | |-------------------|--------------| | proof | Uint8Array | | publicInputs | Uint8Array | | numPublicInputs | number |

Input values are decimal strings ("3", "-7"), keyed by the circuit's declared input names. Throws on a malformed .xbc, unknown input, unsatisfiable witness, or malformed key.

proof and publicInputs are the canonical compressed bytes (identical to the host's proof.bin / public_inputs.bin) — pass them straight to verify. For snarkjs interop, convert them on demand (see proof_to_snarkjs below).

prove does not self-verify. Call verify on the result if you want that check.

preload(circuitXbc, pkBytes)

Parse + cache the .xbc and proving key once (replaces prior cached state).

prove_preloaded(inputs)

Like prove but reuses the artifacts cached by preload. Throws if preload hasn't been called.

verify(vkBytes, proofBytes, publicInputsBytes)

| argument | type | |---------------------|-------------------------------| | vkBytes | Uint8Array | ArrayBuffer | | proofBytes | Uint8Array | ArrayBuffer | | publicInputsBytes | Uint8Array | ArrayBuffer |

Returns true if valid, false if well-formed but not verifying. Throws on deserialization errors.

proof_to_snarkjs(proofBytes)object

Converts the proof Uint8Array from prove() into the snarkjs proof object.

public_inputs_to_snarkjs(publicInputsBytes)string[]

Converts the publicInputs Uint8Array from prove() into the snarkjs public.json array of decimal strings.

const { proof, publicInputs } = prove(xbc, pk, { secret: "3", result: "27" });
const snarkjsProof  = proof_to_snarkjs(proof);
const snarkjsPublic = public_inputs_to_snarkjs(publicInputs);

Security

Prover randomness comes from the platform CSPRNG (crypto.getRandomValues).

Build

cargo install wasm-pack
rustup target add wasm32-unknown-unknown
./build.sh                 # default target: bundler (webpack, vite, …)
./build.sh web             # or: nodejs | bundler | module

The module target (Cloudflare Workers / workerd) is built with wasm-bindgen directly, since wasm-pack can't emit --target module. A release build of the module target will also rebuild dist/bundler/ and copies its optimized wasm (the raw wasm is byte-identical across targets — only the JS glue differs).