69 lines
5.3 KiB
Markdown
69 lines
5.3 KiB
Markdown
# 23. The transparency log
|
|
|
|
A receipt's `at` is what its signer wrote, and a roster is a file a package carries.
|
|
Neither proves that a receipt existed before the key that signed it was revoked, or that the roster a verifier holds is the one the team published.
|
|
A team's transparency log settles both: an append-only record of every receipt, revocation and roster the team publishes, whose state is a Merkle tree root that the team signs and that witnesses may cosign.
|
|
The log is the same tree as receipts and the correction history ([8.5](08-fidelity.md#85-merkle-roots), [11.5](11-corrections.md#115-the-history-root)), with the same proofs.
|
|
Both formats of this chapter are `provisional` ([0.4](00-introduction.md#04-status)): the design follows the specifications that transparency logs share, and the first deployment will shape the details.
|
|
|
|
## 23.1 Entries
|
|
|
|
An entry, `scienting-log-entry/1`, is one item of the tree, `[kind, id, hash]`:
|
|
|
|
| `kind` | `id` | `hash` |
|
|
| --- | --- | --- |
|
|
| `receipt` | The receipt's record ID. | Its record hash ([8.4](08-fidelity.md#84-record-hashes-and-signatures)). |
|
|
| `revocation` | The revocation's record ID. | Its record hash. |
|
|
| `roster` | The store the roster is for. | SHA-256 of the canonical JSON of the roster. |
|
|
|
|
Entries are appended in the order the team publishes them and never removed.
|
|
The leaf hash of an entry is SHA-256 of the byte 0x00 and its canonical JSON, the interior hashes follow RFC 9162, and the root over no entries is SHA-256 of the empty string, as for the history root.
|
|
A roster is logged before any receipt a key it adds may sign, so a verifier can find the roster that governed a receipt by looking at the entries before it.
|
|
|
|
## 23.2 Checkpoints
|
|
|
|
A checkpoint, `scienting-checkpoint/1`, is a signed note in the format transparency logs share: an origin line, the tree size, the root hash in Base64, an empty line, and one signature line per signer.
|
|
|
|
```text
|
|
scient.ing/log/smithlab
|
|
41
|
|
Q2xlYXIgdGV4dCBpcyBub3QgYSByb290IGhhc2guLi4uLi4uLi4=
|
|
|
|
— ana AAAAAAHZ…
|
|
```
|
|
|
|
The origin names the log, and a team's logs are named `scient.ing/log/<store>` or under a domain the team controls.
|
|
A signature line is an em dash (U+2014), a space, the signer's roster key, a space, and Base64 of the signer's four-byte key hash followed by the signature.
|
|
The key hash is the first four bytes of SHA-256 of the signer's name, a newline, the byte 0x01 and the Ed25519 public key; the signature is Ed25519 over the note's first three lines, each ending in a newline.
|
|
A note parsed into JSON has `format`, `origin`, `size`, `root` as hex, `signatures` as `{name, key_hash, value}` and the `note` text itself; the schema is `checkpoint.schema.json`.
|
|
`checkpoint.jsonl` gives a checkpoint over the example paper's receipts and its verification.
|
|
|
|
A checkpoint may carry further signature lines from witnesses: roster keys with the `witness` purpose, held by independent parties, that cosign only a checkpoint consistent with every earlier one they saw.
|
|
A verifier that holds two checkpoints of one log checks a consistency proof between them ([11.5](11-corrections.md#115-the-history-root)); a log that cannot produce one has rewritten its past.
|
|
A project accepts a checkpoint when its origin is the project's log, a key with the role `owner` and the `sign` purpose signed it, and at least the project's `threshold` of its listed witnesses cosigned it ([20](20-projects.md)); `fixtures/records/log/checkpoint` is signed by the team and one witness.
|
|
|
|
## 23.3 What a log settles
|
|
|
|
When a project names a log in its settings ([20](20-projects.md)), a receipt counts toward a level only when the log holds it, and the log's order replaces the records' own times in two rules:
|
|
|
|
1. A revocation of a signer's period revokes the receipts logged before the revocation that fall in the period; a receipt logged after a revocation of its key never counts, whatever its `at` says.
|
|
2. The roster that governs a receipt is the latest roster entry before it.
|
|
|
|
A reader fetches the latest checkpoint, verifies its signatures against the roster and its consistency with the checkpoint it last saw, then verifies inclusion proofs for the receipts it relies on.
|
|
Without a log the rules of [8.6](08-fidelity.md#86-receipt-status) stand, and the `at` of each record is taken at its word.
|
|
|
|
## 23.4 Serving a log
|
|
|
|
A log is served as static files in the tile layout transparency logs share, so that a client fetches only the subtrees it needs and any file server can host a log.
|
|
|
|
| Path | Holds |
|
|
| --- | --- |
|
|
| `checkpoint` | The latest checkpoint note ([23.2](#232-checkpoints)). |
|
|
| `tile/<L>/<N>` | Hash tile N of level L: the 32-byte hashes of the 256 complete subtrees of 256^L entries each that the tile covers, in order. Level 0 holds the leaf hashes. |
|
|
| `tile/<L>/<N>.p/<W>` | The rightmost, partial tile of level L, holding W hashes. |
|
|
| `tile/entries/<N>` and `tile/entries/<N>.p/<W>` | The entries themselves, 256 to a tile, as canonical JSON Lines. |
|
|
|
|
N is written as 3-digit groups, every group but the last prefixed `x`: tile 1234067 is `tile/0/x001/x234/067`.
|
|
A tile at level L holds only the hashes of complete subtrees, so the hashes a partial tree still needs are computed from lower levels, as RFC 9162 computes a root from its subtrees.
|
|
`fixtures/records/log/` is the example paper's log in this layout, and `checkpoint.jsonl` lists its tile paths.
|