Offline · no server · CI-ready
Seal a web archive. Prove any file.
waxseal seals a WACZ web archive with one detached, signed file. It builds a single fingerprint — a Merkle root — over every member and signs it with Ed25519, so anyone can verify the archive offline, or prove that one file belongs to it without shipping the whole archive.
curl -fsSL https://raw.githubusercontent.com/srivtx/waxseal/main/install.sh | sh
Installs the waxseal binary with Bun. It is not published to npm; bunx github:srivtx/waxseal#main runs it without installing. Signing and verification use only local node:crypto.
$ waxseal seal capture.wacz --key archive-key.pem --out capture.seal.jsonarchive: /tmp/opencode/demo.waczseal: /tmp/opencode/refs/demo.seal.jsonroot: 7ce7902d6dc6619e28496d7c717bacfbfb36bc7982b6d424d8d1f11c9218fcf7memberCount: 2algorithm: ed25519signature: 3D0VHjqpApz6TIVAmhlO/R6s... $ waxseal verify capture.wacz -s capture.seal.json --public-key archive-key.pub.pemOKroot: 7ce7902d6dc6619e28496d7c717bacfbfb36bc7982b6d424d8d1f11c9218fcf7signature: validfingerprint: sha256:8b3e7cbe526fdb46b70f4f3a8b2a3992475febd3f02f94a27a3b9395b2d3825ctrusted: no — self-signed seal; pin it with --public-key or --root
What it does
A portable integrity layer that sits on top of the WACZ members, rather than replacing the tools that read and replay them.
- One deterministic Merkle root
- A single root over path-sorted
(normalized path, content SHA-256)pairs. Re-zipping the same logical content yields the same root. - Ed25519 signing
- The root, member count, algorithm,
createdAt, and the archive's byte hash are signed in one canonical payload. - Offline verification
- Rebuild the root, check the signature, and check any proof — no network, no server. Signing and verifying use only local
node:crypto. - Member-only proofs
- One inclusion proof per member shows a single file belongs to the signed root without revealing the rest of the archive.
- Trust pinning
- Pin
--public-keyor--rootout of band. The fingerprint is always printed, andtrusted: yesappears only when the pin matches. - Reproducible seals
- The same archive, key, and
--created-attimestamp produce a byte-identical seal, so seals can be rebuilt and compared in CI.
Quick start
Make a key, seal the archive once, then verify it later — fully offline and pinned to the public key.
# 1. create a key pair$ waxseal keygen --out archive-key # 2. seal once, emit a seal and one inclusion proof per member$ waxseal seal capture.wacz --key archive-key.pem --out capture.seal.json --proofs capture.proofs.json # 3. verify later, fully offline, pinned to the public key$ waxseal verify capture.wacz -s capture.seal.json --public-key archive-key.pub.pem
Every command, flag, exit code, and JSON field is in Usage.
Documentation
The landing page is the pitch. The reference lives on four short pages.
- Commands
- Every command — keygen, seal, verify, proof-verify, and inspect — with its purpose and real output.
- Usage
- Install, every option from
--help, examples, exit codes, and JSON output. - CI
- Verify a seal in a pipeline, offline, with the exit code as the gate and a pinned public key.
- FAQ
- Scope, limitations, and how waxseal compares to the tools around it.
Playground
This demo runs the real, bundled Merkle and inclusion-proof code in your browser. Enter one member per line as path=content, compute the deterministic root, and verify a proof. Nothing is uploaded.
Ed25519 key operations need the CLI
Ed25519 key generation, signing, and signature verification are not available in the browser demo; use the waxseal CLI for keygen, signing, and signature checks. The demo covers the Merkle root and inclusion proofs using a vendored SHA-256 shim, with no signing calls.
Compute
Runs entirely in your browser. Nothing is uploaded.
| Path | Content SHA-256 | Size |
|---|---|---|
| Run the demo to compute member digests. | ||
Inclusion proof
Proof verifier
Calls the real verifyInclusion against the computed root.
Not verified yet.