Local-first cryptographic proof bundles for digital works: hashes, Merkle roots, signatures, and OpenTimestamps evidence.
  • Go 99.5%
  • Makefile 0.5%
Find a file
2026-07-09 18:49:00 +02:00
.proofbundle/2026-07-09/9564d3c Publish ProofBundle attestation 2026-07-09 18:49:00 +02:00
cmd/proofbundle Add optional OpenPGP signing 2026-07-09 18:02:20 +02:00
docs Add optional OpenPGP signing 2026-07-09 18:02:20 +02:00
internal/proof Add optional OpenPGP signing 2026-07-09 18:02:20 +02:00
.gitignore Initial ProofBundle MVP 2026-07-07 16:53:43 +02:00
AGENTS.md Initial ProofBundle MVP 2026-07-07 16:53:43 +02:00
go.mod Initial ProofBundle MVP 2026-07-07 16:53:43 +02:00
Makefile Initial ProofBundle MVP 2026-07-07 16:53:43 +02:00
PROJECT_CONTEXT.md Add optional OpenPGP signing 2026-07-09 18:02:20 +02:00
README.md Publish ProofBundle attestation 2026-07-09 18:49:00 +02:00
TODO.md Add optional OpenPGP signing 2026-07-09 18:02:20 +02:00

ProofBundle

ProofBundle creates portable cryptographic proof bundles for digital works.

It is a local-first CLI: original works stay on your machine. The bundle records a canonical manifest, Merkle root, signed author/custody claim, and optional OpenTimestamps proof.

ProofBundle is not copyright registration and does not replace SIAE, courts, public registries, or legal advice. It produces technical evidence of existence, integrity, temporal priority, and a signed author claim.

Build

make build

The binary is written to bin/proofbundle.

Quick Start

# Create a proof bundle for a directory.
proofbundle create ./my-work --title "Demo Song" --author "Alice"

# Verify the bundle itself.
proofbundle verify my-work.proof.zip

# Verify the original work still matches the bundle.
proofbundle verify my-work.proof.zip --work ./my-work

# Show metadata.
proofbundle info my-work.proof.zip

For deterministic offline tests without OpenTimestamps:

proofbundle create ./my-work --no-stamp

Commands

proofbundle create [options] <file|zip|directory>
proofbundle verify [--work path] [--ots] <bundle.proof.zip>
proofbundle info <bundle.proof.zip>
proofbundle diff <old.proof.zip> <new.proof.zip>
proofbundle keygen [--out path]
proofbundle ots upgrade <bundle.proof.zip>
proofbundle ots verify <bundle.proof.zip>

Input Modes

  • auto: directory as directory, normal file as file, .zip as raw zip bytes.
  • raw: prove exact bytes of a file; for zip this is zip-raw.
  • unpack: prove logical contents of a zip archive with deterministic ordering.
  • directory: prove recursive directory contents.
  • zip-raw: prove exact zip bytes.
  • zip-unpack: prove zip member contents, ignoring zip timestamps/metadata.

Examples:

proofbundle create song.zip --mode raw
proofbundle create song.zip --mode unpack
proofbundle create ./album --private-names
proofbundle create ./album --signer openpgp --signing-key ABCDEF1234567890ABCDEF1234567890ABCDEF12
proofbundle diff album-v1.proof.zip album-v2.proof.zip

Bundle Contents

manifest.json
merkle-tree.json
merkle-root.txt
author-claim.json
signature.ed25519
public-key.txt
signature.openpgp.asc       # when --signer openpgp is used
signer.openpgp.json         # when --signer openpgp is used
timestamp.msg
timestamp-status.json
timestamp.ots              # only when OpenTimestamps stamping succeeds
verification-report.txt

The original work is not included.

Signing

ProofBundle supports two signing modes:

  • ed25519: default local software key, usable by anyone without extra hardware.
  • openpgp: optional detached OpenPGP signature through the external gpg command, useful for existing OpenPGP identities and optional YubiKey-backed signing keys.

By default the CLI uses Ed25519 and creates or reuses:

~/.config/proofbundle/identity.ed25519.json

Generate one explicitly:

proofbundle keygen
proofbundle keygen --out ./identity.ed25519.json

Keep this private key safe. It is not stored in proof bundles.

For optional OpenPGP signing:

proofbundle create ./my-work \
  --signer openpgp \
  --signing-key ABCDEF1234567890ABCDEF1234567890ABCDEF12

Use an OpenPGP fingerprint or key ID for --signing-key; a full fingerprint is recommended. Verification uses gpg --verify against signature.openpgp.asc and author-claim.json.

OpenTimestamps

If the ots command is installed, create attempts to stamp timestamp.msg. If ots is missing or offline, bundle creation still succeeds and records the status in timestamp-status.json.

Later:

proofbundle ots upgrade work.proof.zip
proofbundle ots verify work.proof.zip

Install the OpenTimestamps client separately according to your OS/package manager.

Repository provenance

Public Git snapshots of this repository are attested with ProofBundle itself.

ProofBundle binds a Git archive to a deterministic manifest, Merkle root, signed authorship/custody claim, and OpenTimestamps proof. For this project, the public author claim is signed with the OpenPGP Ed25519 key:

Gabriele Salati <gabriel1@gabrielesalati.eu>
08BBBF34E279618861E2897D03E8E3F46FBDC8AA

This is technical evidence of integrity, timestamping, and signed claim of authorship/custody; it is not copyright registration.

Published attestation:

Development

make check

This runs gofmt, go test ./..., and go vet ./....

Use careful language:

  • It proves that this exact byte sequence or directory state existed before a verifiable timestamp.
  • It proves that the current work matches the manifest and Merkle root.
  • It proves that an Ed25519 key or OpenPGP key signed a claim about that root.

It does not prove by itself:

  • legal copyright ownership
  • originality
  • that no one else created the work earlier
  • that SIAE or legal institutions are unnecessary