# Verification packs

A pack is everything needed to check a set of records offline: the records with their receipts, the service keys, the agent keys and the anchors, in one JSON file. Anyone can check it with the open verifier, without our service, for as long as they keep it.

## The command

The same command is shown everywhere an auditor sees one, and the downloads carry these names:

```bash
npx signafaide verify pack.json \
  --keys https://<service>/.well-known/signafaide-keys.json \
  --agent-keys agent-keys.json \
  --head head.json
```

- `pack.json`: download it from the console, from an auditor link, or with `signafaide export -o pack.json`.
- `agent-keys.json`: the customer writes it with `signafaide keys export -o agent-keys.json`.
- `head.json`: the customer's `.signafaide/head.json`. With it, the check fails if any record was cut from the end of the pack; without it, leave the `--head` line out.

An auditor link offers all three in one download when the customer attaches the keys and the head file. To show what a record said, the customer also gives the content file (`.signafaide/chain/<project>/<env>/<agent>.jsonl`, which holds each content with its salt). See [Verify](/docs/verify).

## What each check means

The verifier prints one line per check: `PASS`, `PENDING` (co-signed, waiting for the public timestamp: an anchor is made every hour and usually confirms within a few hours), `NOT CHECKED` (could not run, for example offline) or `FAIL`. Only `PASS` counts as passed.

| # | Check | What it tells you |
|---|---|---|
| 1 | Envelope schema | Every record is complete and well formed, and belongs to the project and environment the pack names. An empty pack fails: it proves nothing. |
| 2 | Record hashes | Each record still has the fingerprint it had when it was signed: nothing in it was changed. |
| 3 | Client signatures | Each record was signed by one of the customer's own agent keys, valid at the time. The keys come from the customer's file, so the service cannot slip in a key of its own. |
| 4 | Agent chains | Each agent's records follow one another with no gap, no reordering and no time going backwards. |
| 5 | Merkle proofs | Each record is inside the batch the service says it is. |
| 6 | Batch hashes and signatures | The service signed each batch it received. |
| 7 | Batch chain | The service's batches follow one another, so the service cannot drop or swap a batch unnoticed. |
| 8 | Signed heads | The pack holds exactly what the service exported, and each agent's records reach its newest receipt, so none were cut from the end. With the customer's head file this also holds against the service. |
| 9 | drand rounds | Each batch was written after a public randomness round: the earliest it can have been written. |
| 10 | Anchors | Each batch is covered by an hourly anchor that fixes the service's key list. Batches younger than the hour can be pending. |
| 11 | OpenTimestamps | Each anchor has a public timestamp: the latest the batch can have been written. Confirmed only when checked against the public block it names; pending until then. |
| 12 | Content hashes | When content is supplied with its salt, it matches the record's hash. Hash-only records skip this check (not checked). |

## The exact rules

- [Pack format](/docs/packs/format): the file, the export statement the service signs, and where the keys and the head come from.
- [Verifier rules](/docs/packs/rules): what each check tests, rule by rule, and how the result line is written.

Both are generated from the protocol specification, section 7.
