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 · verify
$ 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-key or --root out of band. The fingerprint is always printed, and trusted: yes appears only when the pin matches.
Reproducible seals
The same archive, key, and --created-at timestamp 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.

quick start
# 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.

Merkle root

Leaf order (sorted by path)

No members computed yet.

Per-member content SHA-256
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.