Pack format
Generated from the protocol specification, section 7. For what each check means in plain words, see Verification packs.
The file #
A single JSON file:
{"format":"signafaide-pack/1","generated":"...","project":"...","project_name?":"...","env":"...",
"service_keys":[...],"agent_keys":[{"agent","key_id","public_key","valid_from","valid_to"}],
"filter":{"agents":null,"from":null,"to":null},
"heads":[{"head","head_sig"}],
"records":[{"envelope","key_id","sig","content?","salt?","receipt"}],
"anchors":[{"anchor","anchor_sig","paths":{"<batch_hash>":{"index":0,"path":["..."]}}}],
"export_sig":"..."}project_name is optional: the project's name as the customer named it (1 to 200 characters, no control characters). When present it is part of the export statement, so it is signed; a verifier names the project with it in its first line. filter is the export's filter (agents: null for every agent, or the agent names; from and to: null or a time). heads holds the newest signed head, at export time, of each agent that has records in the pack. Every key entry has a valid valid_from time and a valid_to that is null or a time; anything else makes the pack malformed.
Export statement #
The service signs what the pack covers, so nobody who holds the pack can change it unnoticed:
{"project","project_name?","env","generated","filter","heads":[<each heads[i].head, in pack order>],"records_hash":"..."}project_name is in the statement exactly when it is in the pack. records_hash = sha256(JCS(list)) of every record's receipt.record_hash, in pack order. export_sig is the service's signature over domain export and sha256(JCS(statement)), by a service key active at generated. Every export head's server_time is at or before generated.
Inputs besides the pack #
The service keys must come from a source independent of the pack (--keys <file|url>). The agent keys must too (--agent-keys <file|url>, the customer's §2.5 manifest from signafaide keys export); a key's valid_to is the earlier of the manifest's (the customer's signed retirement) and the pack's agent_keys entry for the same key (the service's record of a revocation or retirement): each can only narrow the window. Keys over plain http:// are accepted only from a loopback address (localhost, 127.0.0.0/8, ::1), with a warning, and then do not count as independent; from any other host they are refused (exit 2). Optional: --head <file>, the client's §8 head.json (the SDK CLIs use the project's own .signafaide/head.json by default); --content; --timestamp-check <url>, an Esplora-style explorer API that confirms public timestamps (default https://mempool.space/api; https://blockstream.info/api also works), or --offline. An explorer over plain http:// is never asked: check 11 is then not checked.