{"_id":"@makerchecker/proof-verifier","_rev":"2-f1175ea5c38ef8b813f60de9a812c404","name":"@makerchecker/proof-verifier","dist-tags":{"latest":"1.2.0"},"versions":{"1.1.4":{"name":"@makerchecker/proof-verifier","version":"1.1.4","keywords":["audit","verification","ed25519","rfc8785","agent-governance","tamper-evident","makerchecker"],"license":"Apache-2.0","_id":"@makerchecker/proof-verifier@1.1.4","maintainers":[{"name":"makerchecker","email":"suleiman@mashinii.com"}],"homepage":"https://github.com/sammysltd/makerchecker#readme","bugs":{"url":"https://github.com/sammysltd/makerchecker/issues"},"bin":{"agent-proof":"src/cli.js"},"dist":{"shasum":"5f8bba5c7d0105389bcc0a353ecd490d2df5125e","tarball":"https://registry.npmjs.org/@makerchecker/proof-verifier/-/proof-verifier-1.1.4.tgz","fileCount":22,"integrity":"sha512-O46EVs8DsnxjsgP4uIYgOv94uW+x2OSZ3rpYRaGXKLxMyDfsoLGPTcATT3ky737k2rvPh8TJelVLrtJUXM4NXg==","signatures":[{"sig":"MEQCIDT9JJMQgq82rdW8buBELhY9cEt7vKSfgqIlix6XE6PoAiABF8nfPaMK7jdwSOUcEsbva6RlhDKNaouzEBG7yk5S9g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@makerchecker%2fproof-verifier@1.1.4","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":136605},"main":"src/index.js","type":"module","_from":"file:makerchecker-proof-verifier-1.1.4.tgz","engines":{"node":">=18.4.0"},"exports":{".":"./src/index.js","./core":"./src/verify-core.js","./node":"./src/node-crypto.js"},"scripts":{"lint":"true","test":"node scripts/test.mjs","typecheck":"true","build:vectors":"node scripts/build-vectors.mjs"},"_npmUser":{"name":"makerchecker","email":"suleiman@mashinii.com"},"_resolved":"/tmp/e94083cec91175f67719d89d844e3ad7/makerchecker-proof-verifier-1.1.4.tgz","_integrity":"sha512-O46EVs8DsnxjsgP4uIYgOv94uW+x2OSZ3rpYRaGXKLxMyDfsoLGPTcATT3ky737k2rvPh8TJelVLrtJUXM4NXg==","repository":{"url":"git+https://github.com/sammysltd/makerchecker.git","type":"git","directory":"packages/proof-verifier"},"_npmVersion":"10.9.8","description":"Standalone, zero-dependency, zero-trust verifier for Agent Action Proof Receipt bundles. Verifies a MakerChecker audit bundle offline with no database or server access.","directories":{},"_nodeVersion":"22.23.1","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/proof-verifier_1.1.4_1783179250740_0.1955379146730427","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@makerchecker/proof-verifier","version":"1.2.0","repository":{"type":"git","url":"git+https://github.com/makerchecker/MakerChecker.git","directory":"packages/proof-verifier"},"description":"Standalone, zero-dependency, zero-trust verifier for Agent Action Proof Receipt bundles. Verifies a MakerChecker audit bundle offline with no database or server access.","license":"Apache-2.0","type":"module","bin":{"agent-proof":"src/cli.js"},"main":"src/index.js","exports":{".":"./src/index.js","./core":"./src/verify-core.js","./node":"./src/node-crypto.js"},"keywords":["audit","verification","ed25519","rfc8785","agent-governance","tamper-evident","makerchecker"],"engines":{"node":">=18.4.0"},"scripts":{"build:vectors":"node scripts/build-vectors.mjs","test":"node scripts/test.mjs","lint":"true","typecheck":"true"},"_id":"@makerchecker/proof-verifier@1.2.0","bugs":{"url":"https://github.com/makerchecker/MakerChecker/issues"},"homepage":"https://github.com/makerchecker/MakerChecker#readme","_integrity":"sha512-lhIaMwABoeXS4EWz+5nxENOdXCizWfL3L3H89wc6L67EiKJtLlkWbfK3JbmeHEx8CZBIctFDzBJpAGy+NUcoqA==","_resolved":"/tmp/87eae1692f95a867fb409846988a3ba7/makerchecker-proof-verifier-1.2.0.tgz","_from":"file:makerchecker-proof-verifier-1.2.0.tgz","_nodeVersion":"22.23.1","_npmVersion":"10.9.8","dist":{"integrity":"sha512-lhIaMwABoeXS4EWz+5nxENOdXCizWfL3L3H89wc6L67EiKJtLlkWbfK3JbmeHEx8CZBIctFDzBJpAGy+NUcoqA==","shasum":"e4d7f8f0e4075fadceaf2dab79fad22c0b179e57","tarball":"https://registry.npmjs.org/@makerchecker/proof-verifier/-/proof-verifier-1.2.0.tgz","fileCount":22,"unpackedSize":137249,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@makerchecker%2fproof-verifier@1.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCd0BlMbT7L+EuSyw+ynwQLyD00SLICZtwbYIALJ3g5wgIhAK6WjJR2S9e4xTAqwhX1F4Yp2BqhfcFSMX+VALFYAPwX"}]},"_npmUser":{"name":"makerchecker","email":"suleiman@mashinii.com"},"directories":{},"maintainers":[{"name":"makerchecker","email":"suleiman@mashinii.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/proof-verifier_1.2.0_1783346121573_0.6362559326925121"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-04T15:34:10.615Z","modified":"2026-07-06T13:55:21.983Z","1.1.4":"2026-07-04T15:34:10.871Z","1.2.0":"2026-07-06T13:55:21.713Z"},"bugs":{"url":"https://github.com/makerchecker/MakerChecker/issues"},"license":"Apache-2.0","homepage":"https://github.com/makerchecker/MakerChecker#readme","keywords":["audit","verification","ed25519","rfc8785","agent-governance","tamper-evident","makerchecker"],"repository":{"type":"git","url":"git+https://github.com/makerchecker/MakerChecker.git","directory":"packages/proof-verifier"},"description":"Standalone, zero-dependency, zero-trust verifier for Agent Action Proof Receipt bundles. Verifies a MakerChecker audit bundle offline with no database or server access.","maintainers":[{"name":"makerchecker","email":"suleiman@mashinii.com"}],"readme":"<div align=\"center\">\n\n# ✅ @makerchecker/proof-verifier\n\n### Prove a MakerChecker audit bundle is intact and who signed it — offline, trusting nothing but the bytes.\n\n`@makerchecker/proof-verifier` re-implements verification from the public [audit specification](../../docs/audit-spec.md) alone — it does **not** import the server, touch a database, or make a network call. Hand it a signed bundle and it tells you whether the hash chain is intact and who signed it. Zero dependencies, fully offline.\n\n[![npm](https://img.shields.io/npm/v/@makerchecker/proof-verifier?color=cb3837&logo=npm)](https://www.npmjs.com/package/@makerchecker/proof-verifier)\n[![License](https://img.shields.io/badge/license-Apache--2.0-informational)](../../LICENSING.md)\n[![Zero dependencies](https://img.shields.io/badge/dependencies-0-brightgreen)](package.json)\n\n</div>\n\n> [!TIP]\n> **Verify a bundle now** — no install, no server, nothing leaves your machine:\n> ```bash\n> npx @makerchecker/proof-verifier verify bundle.json\n> ```\n\n> An auditor trusts this verifier *because* it is not the vendor's server. The\n> code is Apache-2.0 and reproducible; the trust is in the independence.\n\n## Why it exists\n\nA MakerChecker deployment exports a signed, hash-chained record of every agent\naction (`audit export`). The value of that record is that **anyone can check it\nwithout trusting us**. This package is the reference independent checker: a CLI,\nan importable isomorphic core, and a single-file web page that runs entirely in\nthe browser with nothing uploaded.\n\n## CLI\n\n```bash\nnpx @makerchecker/proof-verifier verify bundle.json\n# pin the instance public key (obtained out of band) so a re-signed bundle is rejected:\nnpx @makerchecker/proof-verifier verify bundle.json --key instance-pubkey.pem\n# pipe it, or get machine-readable output:\ncat bundle.json | npx @makerchecker/proof-verifier verify - --json\n```\n\nExit code `0` = verified, `1` = failed, `2` = usage error.\n\n```\nPASS  8 events, full chain (genesis-rooted)\n      head 4c5e1a8a2c226d3…b68e02d4474d46c\n      key  sha256:bb48c332…7fc889d   (public-key fingerprint, abbreviated)\n```\n\n## Browser\n\nOpen [`verifier.html`](./verifier.html) in a recent browser, or save it and open\nit offline. Drop a bundle in; all hashing and Ed25519 verification happen\nlocally via WebCrypto. This is the file you can hand a regulator: it keeps\nworking with no server, no account, and no internet, even after a contract ends.\n\n## Library\n\n```js\nimport { verifyBundle, nodeCrypto } from \"@makerchecker/proof-verifier\";\n\nconst result = await verifyBundle(bundle, nodeCrypto, {\n  expectedPublicKeyPem, // optional out-of-band key pinning\n});\n// { ok: true, count, bundleKind, headHash, keyFingerprint }\n// | { ok: false, reason, reasonCode?, failedSeq?, path? }\n```\n\nThe core (`@makerchecker/proof-verifier/core`) is isomorphic: all cryptography\nis injected through a provider, so the same logic runs under Node and in the\nbrowser.\n\n## What it checks\n\nPer the [audit spec](../../docs/audit-spec.md):\n\n1. **Signature** — Ed25519 over the RFC 8785 canonical signing string.\n2. **Count** — events match the signed count.\n3. **Hash-set digest** — the exact event set and order are bound into the signature.\n4. **Per-event hashes** — every event's SHA-256 recomputes (any altered field fails here).\n5. **Linkage** — full bundles verify complete genesis-rooted `prev_hash` linkage;\n   run bundles verify every event is bound to the signed `run_id`.\n6. **Head & bounds** — head hash and first/last seq match the manifest.\n7. **Key pinning (optional)** — rejects a bundle re-signed with any key but the pinned one.\n\n### Spec-violation verdicts (distinct from tamper)\n\nThe spec requires hashed input to be **I-JSON (RFC 7493)**: every string —\nobject key or value — must be well-formed Unicode. RFC 8785 presumes I-JSON\nand defines no interoperable byte sequence for an unpaired surrogate\n(implementations disagree: ES2019 `JSON.stringify` emits a `\\ud800` escape,\nPython/Go RFC 8785 libraries throw or emit different bytes), so a hash over\nsuch a string can never cross-verify. When a bundle contains one, the verifier\nreturns a **machine-readable spec-violation reject**, deliberately distinct\nfrom a tamper verdict:\n\n```js\n{\n  ok: false,\n  reasonCode: \"ill_formed_string\", // machine-readable verdict class\n  failedSeq: \"9\",                  // the offending event (absent for a manifest string)\n  path: \"$.payload.note\",          // JSON path of the ill-formed string\n  reason: \"event seq 9 contains an ill-formed string (unpaired surrogate) at $.payload.note: ...\"\n}\n```\n\n`ill_formed_string` proves nothing was altered — it says the bundle violates\nthe spec's I-JSON requirement, its hashes were never well-defined, and it must\nnot be accepted. Producers running the fixed pipeline can no longer emit such\nbundles (ill-formed strings are rejected at API ingress with HTTP 400 and by\nthe serializer itself, fail closed). No Unicode normalization is ever applied:\nNFC and NFD strings are distinct bytes, and characters outside JSON's\nmandatory escape set (including astral characters like U+1F600) are hashed and\nemitted literally — the `unicode-literal` vector proves both properties.\n\n## Conformance vectors\n\n[`vectors/`](./vectors) is a public corpus: valid full and run bundles (one\nwith astral + NFC/NFD strings proving literal, unnormalized Unicode handling)\nplus adversarial variants (tampered payload, corrupted signature, truncation,\nreordering, a re-signed foreign-run splice, a wrong-key forgery, and an\nill-formed-string bundle that must be rejected as an I-JSON spec violation),\neach with the verdict a conformant verifier must return in\n[`vectors/index.json`](./vectors/index.json). Any implementation in any language\ncan run these and self-certify.\n\nThe corpus is **deterministic and frozen**: external implementers can pin the\ncommitted vector files by hash. Regeneration is byte-reproducible — every\ntimestamp and id is a fixed constant, event UUIDs are derived from SHA-256 of\na fixed namespace string, and the bundles are signed with the committed\n[`vectors/test-fixture-signing-key.pem`](./vectors/test-fixture-signing-key.pem),\na **deliberately public** test fixture (never a secret, never used outside this\ncorpus; see the header of\n[`scripts/build-vectors.mjs`](./scripts/build-vectors.mjs)). `npm test`\nregenerates into a temp directory and fails on any byte diff against the\ncommitted files, so the corpus cannot drift silently.\n\n```bash\nnpm test            # byte-compares a fresh regeneration, then asserts every verdict\nnpm run build:vectors   # regenerate in place (must be a no-op diff)\n```\n\nThe reimplementation here is cross-checked to be **byte-identical** to the\nproducer's own primitives (`@makerchecker/shared`), so \"verify from the spec\nalone\" is a fact, not a slogan.\n\n## License\n\nApache-2.0.\n","readmeFilename":"README.md"}