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

chiproof

v0.9.1

Published

Verifier SDK for attested, windowed disclosure from ICAO 9303 chip documents. Part of the zkagent project. Exercised end to end against the project's reference scanner and demo on real hardware (a Pixel 6a, a US passport and an NL ID card); no external ad

Readme

chiproof

Status: released (see the version on npm). The zkagent project was closed as a complete experiment (D108) and then revived for tier C (D109); tier C is built and device-checked and shipped in 0.9.0. This package has been exercised end to end against the project's reference scanner and demo on real hardware (a Pixel 6a, a US passport and an NL ID card) — see docs/logs/ in the repository — but it has no external adopter and has not been independently audited. A "verified" verdict from bare mode proves nothing about a person; do not treat it as identity-grade until an evidence plug you trust is configured.

chiproof is the verifier SDK of the zkagent project: a stateless Node library that checks an attested, windowed disclosure derived from an ICAO 9303 chip document — the chip already in a passport or a modern national ID card.

The intended shape, in one paragraph: a phone reads the chip, verifies the issuing government's own signature against a public masterlist, answers exactly one question about the holder (over 18?), and attests that unmodified code did the reading. chiproof verifies that attestation and returns a verdict. No document, date of birth, name or number ever reaches the server. By default no identifier does either — two presentations by the same person are unlinkable. A second, explicitly requested mode adds a pseudonym scoped to one domain, for the cases that need to recognise a returning human.

With no evidence plug configured (the default), the result is bare mode: captcha-grade, not identity-grade — a "verified" verdict means only "a nonce was spent once, on time, under a challenge this process minted"; it says nothing about a person, a document, or a device. The evidence slot and four plugs (signed-receipt/1, zk-passport/1, sig-ed25519/1, sig-p256/1) exist, but an adopter must explicitly configure evidence.require/evidence.accept to leave bare mode (evidence.require may be per-tier — {B: [...]} — so one instance serves a bare tier A next to an evidence-required tier B; a plain array applies at every tier, as in 0.2.0). Each require entry is either a registry-key string (all-of, unchanged) or a non-empty array of registry-key strings — an alternatives group (D31/D36): satisfied when at least one member is present and verifies, e.g. require: { B: [['sig-ed25519/1', 'sig-p256/1']] } lets the device present whichever of the two it can produce. A present-but-invalid group member is never masked by another member passing — it still fails the presentation, exactly like today's all-of items. A plug may declare binds.zktag to additionally tie its evidence to the presented zktag (ctx.zktag; null at tier A). zk-passport/1 is tier-A-only: its underlying circuit has no nonce input, so its nullifier can't double as a stable tier-B/C pseudonym (see the context file below for why). sig-ed25519/1 and sig-p256/1 (D30/D31/D32/D36/D38, FR12, tier ceiling B) are the attester-key family: an app's own device-bound signing key vouches for the challenge binding, algorithm chosen per-device by whichever the app's Keystore actually supports — the two are co-equal reference-default alternatives, not one privileged plug (D31). D38 (2026-09-01): the key is per-origin on the device, so an item may carry data.pubkey (SubjectPublicKeyInfo DER, base64) alongside key_id; the verifier always recomputes key_id from pubkey and refuses a mismatch. An unpinned pubkey is trust-on-first-sight, bound to (scope, zktag) via a new pluggable attesterStore ({ get({scope,zktag}), bind({scope,zktag,key_id,pubkey}) }, InMemoryAttesterStore reference implementation, same conventions as InMemoryNonceStore) — a later presentation for the same (scope, zktag) must carry the identical pubkey, or it's attester_key_mismatch.

Quickstart

import { createVerifier, InMemoryNonceStore } from 'chiproof';

process.env.NODE_ENV = 'test'; // InMemoryNonceStore is test-only; see the context file
const verifier = createVerifier({
  scopeDomain: 'example.com',
  challengeSecret: 'a-secret-at-least-16-bytes-long',
  stores: { nonce: new InMemoryNonceStore({ quiet: true }) },
});
const challenge = verifier.issueChallenge({ tier: 'A', ttlMs: 60_000 });
const verdict = await verifier.verify({
  spec: 'zkagent/1', tier: 'A',
  claim: { over_threshold: true, threshold: 18 }, challenge,
});

Tier C: asking specific questions

Tier C asks a pinned site's chosen questions about the document (expiry bucket, date-of-birth range, nationality, name, document number) and gets back one yes/no per question. It is off unless you turn it on in two places, and the challenge must be signed by an issuer you trust:

import { generateKeyPairSync } from 'node:crypto';
import { createVerifier, InMemoryNonceStore, verifyTierCRefusal } from 'chiproof';

const issuerKeys = generateKeyPairSync('ed25519'); // your challenge-signing key; keep the private half server-side
const verifier = createVerifier({
  scopeDomain: 'example.com',
  challengeSecret: 'a-secret-at-least-16-bytes-long',
  stores: { nonce: new InMemoryNonceStore({ quiet: true }) },
  allowInMemoryStore: true, // examples only: use a persistent NonceStore in production
  tiers: { max: 'C' },                                                                   // 1. allow tier C
  trustedChallengeIssuers: [{ pubkey: issuerKeys.publicKey, key_id: 'my-issuer', maxTier: 'C' }], // 2. trust this signer for C
});

const challenge = verifier.issueChallenge({
  tier: 'C',
  predicates: [
    { name: 'expiry_beyond', months: 6 },                  // months: 3 | 6 | 12
    { name: 'dob_at_least', age: 18 },                     // age: 15 | 16 | 18 | 21 | 60 | 65
    { name: 'nationality_not_in', codes: ['CUB', 'RUS'] }, // 1 to 10 codes
  ],
  ttlMs: 60_000,
  issuer: { privateKey: issuerKeys.privateKey, key_id: 'my-issuer' },
});

// `presentation` is what the phone posts back: { spec: 'zkagent/1', tier: 'C', challenge, answers }.
const verdict = await verifier.verify(presentation);
// verdict.answers: [{ name: 'expiry_beyond', months: 6, result: true }, ...]  one per question, in order

// If the holder declines, the app posts an OpenID4VP error; classify it:
const refusal = verifyTierCRefusal({ error: 'access_denied', state }); // { ok: true, allowed: false, refused: true, ... }
  • Read verdict.answers[].result, never verdict.allowed. allowed: true only means "a well-formed answer to exactly what you asked arrived". A result: false is a real answer, not a failure.
  • The refusal is generic. verifyTierCRefusal returns the same verdict for every cause (D110); you cannot tell why the holder said no. You match state to your own transaction.
  • Limits, checked when you issue the challenge (issueChallenge throws, and validateTierCPredicates(list) returns {ok:false, reason} without throwing): an exclusion set holds at most 10 country codes (D102), and a request carries at most one nationality_is and at most one nationality_not_in (D118, reason nationality_asked_more_than_once), and at most one document_number_is (D119, reason document_number_asked_more_than_once). Other questions are not capped.
  • Without tiers: { max: 'C' } and a trustedChallengeIssuers entry with maxTier: 'C', verify() returns tier_exceeds_max or signature_required_at_tier_c.

The full contract is in chiproof.context.md.

Full integration guide

Every config option, the complete public API, the NonceStore and evidence-plug extension contracts, the threat model, and the sharp edges live in chiproof.context.md — read that (not the source) to wire this library up, or point an integrating agent at it directly.

Running the tests

cd packages/chiproof
node --test

Tests are split per AGENT_RULES.md: tests/unit/ covers the pure logic (verdict.js, canonical.js); tests/integration/ exercises challenge.js, index.js (boot checks) and verify() against the real in-memory store and real Ed25519 keys; tests/e2e/ runs against the gitignored spikes/m1-zk/out/ artefacts and skips cleanly when they or bb are absent.

What this is not

  • Not a zero-knowledge proof by itself: bare mode is captcha-grade. The zk-passport/1 evidence plug verifies a third-party zero-knowledge proof, validation-grade, tier A only — see chiproof.context.md. (amended 2026-08-30, D24/D25) Absent that plug, the verifier checks a hardware attestation that trustworthy code computed an answer; it does not check a proof it could verify itself. The accurate description is attested windowed disclosure. See the design doc.
  • Not an identity provider, wallet, issuer, or certificate authority.
  • Not certified under any regulatory scheme, and not claiming to satisfy any legal age-verification requirement anywhere.

Design

License

Apache-2.0