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

@zkthunder_/sdk

v0.2.0

Published

Zero-knowledge proofs for Robinhood Chain: lineage bundles, range proofs and trustless anchors, generated locally with no dependencies, plus a tiny client for the deployed zkThunder contracts.

Readme

@zkthunder_/sdk

Zero-knowledge proofs for Robinhood Chain, generated locally with no dependencies, plus a tiny read-only client for the deployed zkThunder contracts. Everything the zkthunder.net labs do, as library calls.

  • Pedersen commitments on secp256k1: perfectly hiding, binding under discrete log.
  • Lineage bundles: two hidden values, proofs they are well formed, and a proof they link.
  • Range proofs: a hidden value is at least a public threshold (32 bit range).
  • Bound bundles for the trustless lineage: commitments that provably open to public roots.
  • Calldata encoders for every deployed contract, and a client that verifies on chain over plain JSON-RPC.

Secrets never leave your process. The outputs are commitments, proofs and booleans.

Install

npm install @zkthunder_/sdk

Node 18 or newer (uses fetch and BigInt). No other dependencies.

Private eligibility with PrivateGate

A user proves that a hidden balance is at least a threshold, for a named purpose, bound to the gate contract and to their own address. The gate stores the threshold; any contract can then ask isEligible without the balance ever appearing on chain.

const zk = require("@zkthunder_/sdk");

const GATE = "0x...";                       // a deployed PrivateGate
const user = "0xYourAddress";
const ctx = zk.gateContext(GATE, user, "tier-1 access");   // keccak256(abi.encode(gate, user, purpose))

const { proof, commitment } = zk.proveRange({ value: 1250n, threshold: 1000n, ctx });
// send from `user`: to = GATE, data = zk.encodeGateProve("tier-1 access", proof)
// afterwards, from anywhere:
const chain = new zk.Chain();
await chain.isEligible(GATE, user, "tier-1 access", 1000n);   // true, and the 1250 was never revealed

The proof is useless anywhere else: another address, another gate or another purpose changes the context, and the verifier folds the context into every challenge.

Verify a range proof against the deployed verifier

const ctx = zk.context("my-app", "proof-of-reserves", "2026-09");
const rg = zk.proveRange({ value: 5_000_000n, threshold: 1_000_000n, ctx });
await new zk.Chain().verifyRange(rg.proof, ctx);   // true: the RangeVerifier on mainnet accepts it

To publish a public receipt from your own address, send zk.encodeAttest(rg.proof, ctx) to zk.MAINNET.rangeVerifier; it emits RangeVerified(by, ctx, threshold, commitmentDigest).

Read and audit the trustless lineage

const chain = new zk.Chain();
const head = await chain.lineage();       // { lastSeq, lastEndBlock, lastRoot, latestBlock }
const audit = await chain.auditAnchor();  // re-reads the end block from the node and compares
console.log(audit.ok, audit.rootMatchesBlock, audit.linksToPrevious);

Every root in the lineage was extracted by the contract from a block header it checked against the chain's own block hash. No caller ever supplies a root.

Lineage bundles and the public registry

const ctx = zk.context("my-app/lineage", String(Date.now()));
const lin = zk.proveLineage("previous state", "new state", ctx);
await new zk.Chain().verifyLineage(lin.proof, ctx);                 // LineageVerifier says yes
// record it: send zk.encodeSubmit(lin.proof, ctx) to zk.MAINNET.publicProofs

V2: full-coordinate verifiers on BN254

The same constructions on the BN254 curve, where the EVM has built-in point addition and multiplication, so the V2 verifiers compute every scalar multiplication themselves and compare whole points instead of 160 bit addresses. Deployed on mainnet on 13 September 2026; the anchors and the gate still use the V1 verifiers until the audit has compared the two, so use V2 for your own verification and keep V1 for anything that feeds the live contracts. V1 and V2 proofs are not interchangeable.

const rg = zk.proveRangeV2({ value: 1250n, threshold: 1000n, ctx: zk.context("my-app", "balance-check") });
await new zk.Chain().verifyRangeV2(rg.proof, rg.ctx);      // true, checked on whole curve points
const lin = zk.proveLineageV2("previous state", "new state", ctx);   // 17 words instead of 23
await new zk.Chain().verifyLineageV2(lin.proof, ctx);

API

| Function | Purpose | | --- | --- | | commit(value, blinding?) | Pedersen commitment to a 32 byte value (text is hashed) | | proveLineage(prev, out, ctx) / verifyLineage(proof, ctx) | 23 word bundle for LineageVerifier | | proveRange({ value, threshold, ctx, blinding? }) / verifyRange(proof, ctx) | range proof for RangeVerifier | | proveTrustless(prev, out, ctx) / verifyTrustless(proof, ctx, prev, out) | 37 word bound bundle for TrustlessAnchor | | commitV2, proveLineageV2 / verifyLineageV2, proveRangeV2 / verifyRangeV2, proveTrustlessV2 / verifyTrustlessV2 | the same on BN254 for the V2 verifiers (17, 291 and 23 words) | | context(...parts), purposeId(name), gateContext(gate, user, purpose) | context words that bind proofs to their use | | encodeVerify, encodeVerifyBound, encodeSubmit, encodeAttest, encodeGateProve, encodeIsEligible | calldata for the deployed contracts | | new Chain({ rpcUrl?, addresses? }) | verifyLineage, verifyRange, verifyTrustless, verifyLineageV2, verifyRangeV2, verifyTrustlessV2, isEligible, lineage, record, auditAnchor | | MAINNET | deployed addresses on chain 4663 |

Sending transactions is left to whatever wallet library you already use: the encoders return calldata, and MAINNET has the addresses.

Limits, stated plainly

  • Range proofs cover a 32 bit difference between value and threshold and cost about 1.9 million gas to verify on chain. Zero is not a valid threshold.
  • The V1 verifiers, which the live anchors and the gate use, compare 160 bit point addresses (the ecrecover trick). The V2 verifiers check whole points on BN254 and are deployed; the anchors switch to them after the audit.
  • These proofs establish commitment structure and lineage linkage. They do not prove a state transition was computed correctly; that is the zkVM tier.

Test

node test.js

Runs the local checks, then verifies fresh proofs against the mainnet contracts when the RPC is reachable.

Apache-2.0.