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

@allfeat/ats-zkp-wasm

v0.1.1

Published

Allfeat Time Stamp Song Commitment Circuit in Arkworks (BN254, Groth16 + Poseidon)

Readme

ATS-ZKP-WASM – WebAssembly Bindings for Allfeat ZKP

A WebAssembly module exposing the ATS-ZKP cryptographic primitives and zero-knowledge proof helpers to JavaScript/TypeScript applications. It is designed to be used in Next.js, Node.js, and browser environments to compute musical metadata hashes, commitments, and zk-SNARK proofs without exposing Arkworks internals.

Overview

The ats-zkp-wasm crate is a thin WASM façade on top of ats-zkp. It provides a minimal, JS-friendly API with hex strings and plain objects as inputs/outputs, and gives you four high-level functions:

  • build_bundle(title, audioBytes, creators, timestampBigInt) -> { bundle } Computes:

    • hash_title, hash_audio, hash_creators
    • a fresh random secret
    • Poseidon commitment and nullifier Returns everything as hex strings. Note: bundle.timestamp is the timestamp encoded as an Fr hex, ready to pass to proof/verify.
  • calculate_commitment(title, audioBytes, creators, secretHex) -> commitmentHex Computes the Poseidon hash commitment from the provided inputs using an existing secret:

    • hash_title, hash_audio, hash_creators (computed internally)
    • commitment = Poseidon(hash_title, hash_audio, hash_creators, secret) Returns the commitment as a hex string. Use this when you already have a secret (e.g., from a previous build_bundle call) and need to recompute or verify the commitment.
  • prove(pkHex, secretHex, publicsArray) -> { proof, publics } Generates a Groth16 proof using the compressed PK (0x-hex) and 6 public inputs in this exact order: [hash_title, hash_audio, hash_creators, commitment, timestamp, nullifier].

  • verify(vkHex, proofHex, publicsArray) -> boolean Verifies a proof using the compressed VK (0x-hex) and the same 6 publics (0x-hex) in the same order.

All heavy logic remains in ats-zkp; this crate only exports the essential functions to JS.

Prerequisites

Install wasm-pack:

curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh

Building

For Next.js / Bundler (default)

wasm-pack build --target bundler --out-dir pkg

For Node.js

wasm-pack build --target nodejs --out-dir pkg-node

For Browser (ES Modules)

wasm-pack build --target web --out-dir pkg-web

Testing

Run Rust tests:

cargo test

Run WASM tests:

wasm-pack test --node

Running the JavaScript Example

An example script is included in js-example/example.js.

  1. First, build the Node.js bindings:
wasm-pack build --target nodejs --out-dir pkg-node
  1. Move into the js-example/ folder:
cd js-example
  1. Run the example with Node.js:
node example.js

This will:

  • Read a sample audio file (sample-audio.mp3)
  • Build a ZKP input bundle (build_bundle)
  • Generate and print a Groth16 proof (prove)

Integration in TypeScript/JavaScript Applications

Next.js Integration

  1. Build the WASM module:
wasm-pack build --target bundler --out-dir pkg
  1. Copy the pkg folder to your Next.js project (e.g., src/lib/ats-cert-generator)

  2. Configure Next.js for WASM support in next.config.ts:

import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  webpack: (config) => {
    // Enable async WebAssembly
    config.experiments = {
      ...config.experiments,
      asyncWebAssembly: true,
    };

    // Ensure .wasm files are handled as async webassembly
    config.module.rules.push({
      test: /\.wasm$/,
      type: "webassembly/async",
    });

    return config;
  },
};

export default nextConfig;
  1. Use in your Next.js components:
// app/components/ZkpDemo.tsx (or any client component)
"use client";

import { useState, useRef } from "react";

export default function ZkpDemo() {
  const [loading, setLoading] = useState(false);
  const [result, setResult] = useState<string>("");
  const fileRef = useRef<HTMLInputElement | null>(null);

  const onRun = async () => {
    if (typeof window === "undefined") return; // guard SSR

    try {
      setLoading(true);
      setResult("");

      // 1) Dynamically load the wasm-bindgen JS and init the WASM
      const init = (await import("@/lib/ats-zkp-wasm/ats_zkp_wasm.js")).default;
      const { build_bundle, prove, verify } = await import(
        "@/lib/ats-zkp-wasm/ats_zkp_wasm.js"
      );
      await init(); // VERY IMPORTANT: initialize the wasm module

      // 2) Read the audio file as Uint8Array
      const file = fileRef.current?.files?.[0];
      if (!file) {
        setResult("Please choose an audio file first.");
        return;
      }
      const buf = new Uint8Array(await file.arrayBuffer());

      // 3) Prepare inputs (creators must match JsCreator)
      const creators = [
        { fullName: "Alice", email: "[email protected]", roles: ["AT"] },
      ];
      const title = "Song Title";
      const timestamp = BigInt(Math.floor(Date.now() / 1000)); // u64-safe

      // 4) Build the bundle (hashes, secret, commitment, nullifier)
      const { bundle } = build_bundle(title, buf, creators, timestamp);

      // 5) Prove using your PK (hex string, 0x-prefixed, compressed)
      //    You can import it or fetch it from your API/secrets manager.
      const { PK } = await import("@/lib/ats-zkp-wasm/pk.js");
      const publics = [
        bundle.hash_title,
        bundle.hash_audio,
        bundle.hash_creators,
        bundle.commitment,
        bundle.timestamp, // already Fr-hex from build_bundle
        bundle.nullifier,
      ];
      const { proof, publics: publicsProof } = prove(PK, bundle.secret, publics);

      // 6) Verify using your VK (hex string, 0x-prefixed, compressed)
      const { VK } = await import("@/lib/ats-zkp-wasm/vk.js");
      const ok = verify(VK, proof, publicsProof);

      setResult(
        [
          `secret: ${bundle.secret} (keep this PRIVATE)`,
          `proof: ${proof}`,
          `verify: ${ok}`,
        ].join("\n")
      );
    } catch (err) {
      // Errors are forwarded from Rust via `JsValue::from_str`, so they arrive as strings
      console.error("ZKP flow failed:", err);
      setResult(`Error: ${String(err)}`);
    } finally {
      setLoading(false);
    }
  };

  return (
    <div className="space-y-4">
      <input ref={fileRef} type="file" accept="audio/*" />
      <button onClick={onRun} disabled={loading}>
        {loading ? "Running..." : "Run ZKP demo"}
      </button>
      <pre style={{ whiteSpace: "pre-wrap" }}>{result}</pre>
    </div>
  );
}