provared 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +1062 -0
  2. package/LICENSE +202 -0
  3. package/LICENSE-CC-BY-4.0.txt +396 -0
  4. package/README.md +689 -0
  5. package/bin/provared-check.mjs +565 -0
  6. package/bin/provared-headers.mjs +110 -0
  7. package/docs/threat-model.md +997 -0
  8. package/net/headers.js +403 -0
  9. package/package.json +57 -0
  10. package/page/check-page.js +162 -0
  11. package/page/index.html +47 -0
  12. package/page/render.js +530 -0
  13. package/page/style.css +150 -0
  14. package/samples/office-supplies.expected.json +82 -0
  15. package/samples/office-supplies.jsonl +10 -0
  16. package/samples/office-supplies.show.json +59 -0
  17. package/spec/provared-format.md +1672 -0
  18. package/src/actions.js +90 -0
  19. package/src/approval.js +73 -0
  20. package/src/blockstamp.js +198 -0
  21. package/src/book.js +2232 -0
  22. package/src/check.d.ts +21 -0
  23. package/src/check.js +15 -0
  24. package/src/compare.js +276 -0
  25. package/src/cover.js +198 -0
  26. package/src/der.js +192 -0
  27. package/src/encoding.js +286 -0
  28. package/src/fields.js +94 -0
  29. package/src/guard.js +171 -0
  30. package/src/headers.js +380 -0
  31. package/src/index.d.ts +2 -0
  32. package/src/index.js +37 -0
  33. package/src/jws.js +235 -0
  34. package/src/keys.js +149 -0
  35. package/src/pass.js +67 -0
  36. package/src/passkey-browser.d.ts +20 -0
  37. package/src/passkey-browser.js +171 -0
  38. package/src/recorder.js +1115 -0
  39. package/src/seal.js +133 -0
  40. package/src/service.js +124 -0
  41. package/src/signatures.js +147 -0
  42. package/src/slip.js +401 -0
  43. package/src/standing.js +181 -0
  44. package/src/stub.js +140 -0
  45. package/src/timestamp.js +351 -0
  46. package/src/tools.js +192 -0
  47. package/src/tree.js +143 -0
  48. package/src/types.d.ts +628 -0
  49. package/src/webauthn.js +119 -0
@@ -0,0 +1,997 @@
1
+ # Threat model — Provared, draft version 0
2
+
3
+ This document lists who might attack a Provared record, what each part
4
+ protects, and what it does not protect. It was written before the code,
5
+ and it is kept in step with the code: every refusal in section 8 names the
6
+ test that proves it.
7
+
8
+ It covers what is built in draft version 0: the Slip (the permission a
9
+ person signs), with its limits, conditions and stated rules; the Stub
10
+ (the receipt for one action); the countersignature; the person's approval
11
+ of one action; a service's refusal and its terms for agents; the chain of
12
+ stubs; the book; the tree of fingerprints; the Seal, with outside
13
+ time-stamps from a service and from a block of a public blockchain; the
14
+ one-page proof; cancelling a slip, and the agent's acknowledgement of a
15
+ cancellation; vouching for a name; covered fields; passing a slip on to a
16
+ helper agent; the check before acting; and the stub writer beside an
17
+ agent. It does not cover parts that are not built: the recorder service,
18
+ and a public place where seals are kept.
19
+
20
+ *Evidence, not a verdict.* A record shows what was signed and by which
21
+ keys. People decide what it means.
22
+
23
+ ## 1. Who might attack
24
+
25
+ | Name | Who | What they can do | What they want |
26
+ |---|---|---|---|
27
+ | A1 | An insider at the organisation that runs the agent | Reads and edits the book; may hold the agent's keys | To change or remove history |
28
+ | A2 | A holder of a copy of the book (later: the recorder's operator) | Reads everything in the book; can drop, reorder, cut short or swap entries | To change history, or to learn what the records say |
29
+ | A3 | The agent itself, faulty or taken over | Signs anything with the agent's keys | To act outside its slip, or to hide that it did |
30
+ | A4 | The service the agent deals with | Signs with its own keys; may refuse to countersign | To deny what happened, or to claim what did not |
31
+ | A5 | A thief of the agent's keys | Signs as the agent | To act as the agent |
32
+ | A6 | A forger with no passkey | Writes any bytes they like | To make a slip the person never signed, or to widen one |
33
+ | A7 | A stranger who feeds records to a checker | Chooses every byte of the record | To crash the checker, to make it show a pass, or to run a script in the checking page |
34
+ | A8 | A future attacker with a large quantum computer | Forges signatures made with today's common methods (Ed25519, ECDSA, RSA) | To forge old records |
35
+ | A9 | A taken-over device or signing page | Shows the person one thing and asks the passkey to sign another | To get a slip signed that the person did not mean |
36
+
37
+ ## 2. Limits that are true of every part
38
+
39
+ - **A9 wins.** If the person's device or the signing page is taken over,
40
+ the person can be made to sign a slip they did not mean. A passkey
41
+ proves that the device signed and that it confirmed someone by
42
+ fingerprint, face or PIN. It does not prove who was holding the device,
43
+ nor that they read what they signed.
44
+ - **The record shows what was recorded, not what was left out.** An agent
45
+ that acts and writes no stub leaves no trace here. The gap may show
46
+ against the other side's own records.
47
+ - **Times inside records are the signer's own word.** Only an outside
48
+ time-stamp, from a service the person checking has named as trusted,
49
+ proves that entries existed by a time. Entries after the last such
50
+ time-stamp have no proven time. See sections 5 and 6a.
51
+ - **Names are labels.** The name of a person, an agent or a service in a
52
+ record is text chosen by whoever wrote it. Only keys are checked. A
53
+ checker must compare the issuer's key with one it already trusts, or
54
+ name an organisation whose vouching record stands behind the name
55
+ (section 6b).
56
+ - **The passkey signature is of today's kind.** No device offers a
57
+ quantum-safe passkey. Against A8, a slip is protected once it sits
58
+ under a seal, whose three signatures include two quantum-safe ones.
59
+ The outside time-stamps themselves are of today's kind.
60
+ - **A signature that cannot be checked is not a pass.** Where a device
61
+ has no built-in ML-DSA, the checker says so, and never reports the
62
+ record as intact. An entry none of whose signatures the device could
63
+ check is not treated as evidence: what it says is not shown, and it is
64
+ not compared with its slip.
65
+ - **A record does not show that an action was wise, lawful or wanted.**
66
+ - **A badly written slip is faithfully recorded as a badly written slip.**
67
+
68
+ ## 3. The Slip
69
+
70
+ **Protects.** That the permission was signed by the passkey whose public
71
+ key the slip names, on the website the slip names, with the person
72
+ confirmed by the device, and that nothing in it has changed since.
73
+
74
+ **From whom.** A6 (cannot make or widen a slip without the passkey), A3
75
+ and A5 (cannot change the agent's own permission), A2 (cannot alter a
76
+ slip in the book).
77
+
78
+ **How.** The passkey signs a challenge that is the SHA-256 fingerprint of
79
+ the slip's exact signed bytes. Those bytes begin with a label that says
80
+ "this is a Provared slip", so a signature made for a slip can never pass
81
+ as a signature on a stub, a countersignature or a sign-in. The checker
82
+ follows the checking steps of the Web Authentication standard.
83
+
84
+ **Does not protect.**
85
+
86
+ - Against A9, as above.
87
+ - Against a person who signs a slip that is wider than they meant.
88
+ - Against A8, until the slip sits under a seal (section 2, and section
89
+ 6a).
90
+ - Against a cancellation that never reaches the agent or the book: see
91
+ section 6b. Slips should still be short-lived.
92
+ - Who the issuer is. The slip proves which key signed, not whose key it
93
+ is.
94
+
95
+ ## 4. The Stub and the countersignature
96
+
97
+ **Protects.** That the agent's keys signed this exact statement of what
98
+ was done, under this exact slip, at this place in the chain. With a
99
+ countersignature: that the service's keys signed "it happened with me"
100
+ for this exact stub.
101
+
102
+ **From whom.** A2 and A6 (cannot make or change a stub without the
103
+ agent's keys). A4 cannot deny a countersigned stub, and cannot forge the
104
+ agent's half. A3 cannot forge the service's half. A8 must break both
105
+ Ed25519 and ML-DSA-87: each stub and each countersignature carries both,
106
+ and counts only if both check.
107
+
108
+ **How.** Each signature covers a label that names the kind of record, so
109
+ a stub cannot pass as a countersignature. The stub names the slip's
110
+ fingerprint, the fingerprint of the stub before it, the service dealt
111
+ with and its own unique number. The countersignature names the stub's
112
+ fingerprint.
113
+
114
+ **Does not protect.**
115
+
116
+ - A one-sided stub (no countersignature) proves what the agent's side
117
+ said. It is weaker evidence of what the other side did, and it is
118
+ always shown as one-sided.
119
+ - Against A5 before the theft is noticed: stubs signed with stolen keys
120
+ check as the agent's. Short-lived slips limit the harm.
121
+ - Against A1 or A3 writing a false stub with the agent's own keys. A
122
+ countersignature is what makes a stub more than one side's word.
123
+ - The documents themselves. A stub holds fingerprints of documents, not
124
+ the documents. Whoever keeps the documents must keep them.
125
+
126
+ ## 4a. Limits, conditions, approvals and the other side's records
127
+
128
+ **Protects.** That what the person allowed is stated exactly, and that a
129
+ checker compares every stub with it in one fixed way: totals, the size of
130
+ each action, counts, periods, a countersignature or the person's own
131
+ approval where the slip asks for one, and the kinds of action the slip
132
+ forbids. That an approval was signed by the passkey the slip names, for
133
+ exactly one action. That a refusal or a set of terms was signed by the
134
+ keys it gives.
135
+
136
+ **From whom.** A3 cannot make an approval: only the person's passkey can.
137
+ An approval for one action cannot be moved to another action, another
138
+ amount, another service, another document or another slip. In a whole
139
+ book it cannot be used twice; single pages of a Show cannot show a second
140
+ use, and say so. A3 cannot forge a countersignature, so where the slip asks
141
+ for one, an action the other side did not confirm shows as outside the
142
+ slip. A4 cannot be made to seem to have refused or to have stated terms:
143
+ both need its keys.
144
+
145
+ **How.** Each kind of record has its own label, so an approval cannot
146
+ pass as a slip, nor a refusal as a countersignature. An approval names
147
+ the slip and repeats the action, the amount, the service and the
148
+ documents; the stub names the approval's fingerprint; a checker compares
149
+ all of them. A period is counted backwards from each stub in whole
150
+ seconds, so there are no calendar days or time zones for two checkers to
151
+ disagree about. Totals are added as whole numbers of any size.
152
+
153
+ **Does not protect.**
154
+
155
+ - **A rule of conduct is not checked.** "Never claim to be a human being"
156
+ is the person's signed instruction. Nothing in a record can show that
157
+ the agent kept it. Only a kind of action ("never destroys") is compared
158
+ with stubs, and only for actions named from the shared list.
159
+ - **An agent that names its action falsely.** A stub says what the agent
160
+ says it did. An agent that deletes data and writes "read" is caught
161
+ only by the other side's records.
162
+ - **Periods rest on the times in stubs**, which are the agent's own word
163
+ unless an outside time-stamp you trust covers them. An agent can write a false time to
164
+ stay inside a period. A total over the whole life of the slip does not
165
+ have this weakness.
166
+ - **An approval shows that the passkey approved.** It does not show that
167
+ the person read what they approved, and against A9 it shows nothing.
168
+ An approval can be signed after the action: only an outside
169
+ time-stamp you trust, on a seal after the action, bounds it.
170
+ - **A refusal is one side's word**, as a one-sided stub is. A4 can write
171
+ a refusal for a request that was never made. A checker shows it as the
172
+ service's statement and never counts it against the agent.
173
+ - **A refusal can be left out.** Whoever keeps the book can leave a
174
+ refusal out of it. It is strongest in the service's own book.
175
+ - **Terms do not show consent to one action.** They show what the service
176
+ said it accepts. Only a countersignature shows that the service
177
+ confirmed this action.
178
+ - **A stub or a refusal under a slip that this device could not
179
+ confirm** is not shown and not compared, whatever its own signatures
180
+ say: the keys it was checked against came from that slip.
181
+ - **The check before acting is not evidence.** It helps whoever runs the
182
+ agent to stop an action. A taken-over agent does not ask. Nothing in a
183
+ record shows whether the check was made.
184
+ - **Two stub writers on copies of one book.** One stub writer takes its
185
+ actions one after the other, each against the book as the one before
186
+ left it. Two writers on two copies know nothing of each other: both
187
+ may be allowed an action that together passes a limit, and their stubs
188
+ will not fit one chain. Keeping one writer to a chain is the business
189
+ of whoever runs the agent.
190
+ - **An action that never ends.** The stub writer waits for an action it
191
+ is taking, because it cannot know what happened. The other side is
192
+ given a set time to countersign (30 seconds unless told otherwise),
193
+ after which the stub is written one-sided. In Node.js a call to the
194
+ writer made by its own action, while that action runs, is refused at
195
+ once. A browser cannot tell, and neither can Node.js where the action
196
+ waits for some other part of the program that calls the writer: such a
197
+ call waits for ever.
198
+ - **The stub writer's clock.** `act` takes an action at the time its
199
+ clock gives, and refuses a date handed to it that is more than 300
200
+ seconds from that clock either way; nothing is written that is dated
201
+ more than 300 seconds ahead of it. The clock is the device's own, or
202
+ the one the caller gives. A wrong clock gives wrong dates, and `record`
203
+ writes any earlier date the caller states: until an outside time-stamp
204
+ covers a stub, its date is the agent's own word.
205
+ - **What the stub writer is handed** (the request, an approval, what the
206
+ other side hands back) is copied when it is handed over, and the copy
207
+ is what is checked and written. `record` hands a stub to the other
208
+ side only once it has passed the check of the whole book, so the other
209
+ side is never left holding a stub that the writer then refused.
210
+ - **An approval dated ahead of the clock.** The stub writer writes no
211
+ approval dated more than 300 seconds ahead of its clock, as it writes
212
+ no stub and no countersignature dated so.
213
+ - **Cancellations the stub writer keeps.** A writer serves one slip. Of
214
+ the cancellations it cannot add to its book, it keeps every one of its
215
+ own slip; any one is enough to stop it. A cancellation of another slip
216
+ that is handed to `add` is nothing to this writer and is not kept.
217
+ Copies of other slips' cancellations, or of cancellations the book
218
+ already holds, that were given when the writer was opened give way to
219
+ one that matters, so no number of them can crowd it out.
220
+ - **The agent's tools behind the stub writer** (`recordTools`). Each
221
+ call asks first, runs the tool only if the slip allows the action, and
222
+ writes the stub; a call that is not allowed throws, and the tool is
223
+ not run. The arguments are copied when the call is made: the copy is
224
+ what the fingerprint in the stub is made from, and what the tool is
225
+ run with. Each function a tool is described by is handed a copy of
226
+ its own and is called without the description, and what a tool is,
227
+ is fixed when it is put behind the writer, so nothing done
228
+ afterwards, by the caller or by the tool's own functions, changes
229
+ what is recorded or run. A
230
+ list with a gap in it, or with a named member, is not JSON: such
231
+ arguments have no fingerprint, and the tool is not run with them. The
232
+ person is asked to approve only where their approval is the one thing
233
+ missing. It protects only the tools that are put behind it: an agent
234
+ that can reach a tool some other way leaves no stub. The fingerprint
235
+ of the arguments fixes what was asked for without holding it; where
236
+ the arguments are few and easy to guess, the fingerprint can be
237
+ guessed.
238
+ - **The check before acting refuses more in one case.** An action that
239
+ would add to a period which a stub dated after it already overfills is
240
+ refused, though a checker would report nothing new for it.
241
+ - **A cancellation the stub writer cannot add to its book as it was
242
+ handed over** is not lost, if the person signed it. Where what stands
243
+ beside it is at fault (a faulty time-stamp, a member that cannot be
244
+ written as a line of a book, such as a list with a gap in it), the
245
+ writer adds the cancellation with the time-stamps that pass their
246
+ check, or by itself, and the book holds it. Where it cannot be added even so (a
247
+ date ahead of the clock), the writer keeps it as the person's own copy
248
+ and allows nothing more under the slip; it writes it into the book, at
249
+ its next call, once its clock has reached that date. In both cases the
250
+ call fails, and the error says what was done. Every such cancellation
251
+ of the writer's slip is kept, not only the first; one that was kept
252
+ takes the time-stamps it is handed over with later, merged with those
253
+ it holds: each is judged by itself, those the writer counts come
254
+ first, four at most. So a time-stamp from a service the writer was not
255
+ told to trust never keeps out one it counts. A cancellation that was given when the writer was opened, and
256
+ that the book does not hold, is written into the book in the same
257
+ way, takes a time-stamp in the same way, and stops the writer from the
258
+ start. One that the book already holds without a time-stamp stays as
259
+ it is: a line of a book is not changed. The writer is stopped before
260
+ it reads its clock, so a clock that fails while a cancellation is
261
+ handed over does not lose it, nor the sound time-stamps or the
262
+ acknowledgements handed over with it; a clock that gives anything but
263
+ a time counts as a clock that failed. A time-stamp handed over for a cancellation that the
264
+ writer holds is taken before anything is written into the book, so it
265
+ is not lost where the cancellation's date has come in the meantime.
266
+ - **A cancellation the stub writer keeps lives only in that writer**
267
+ until it is written into the book. A writer opened again from the book
268
+ alone knows nothing of it, and takes actions again. This is a stated
269
+ limit. The writer hands back what it holds (`cancellations()`), each
270
+ with the acknowledgement it signed: whoever runs the agent keeps that
271
+ with the book, and hands it in again when a writer is opened. The
272
+ writer opened again then hands back the same acknowledgement, not a
273
+ second one; an acknowledgement that still waits to follow its
274
+ cancellation into the book is handed back too, and the writer opened
275
+ again writes it. An acknowledgement handed over with a cancellation is
276
+ taken as the agent's own only if it checks by itself: one that does
277
+ not check is never handed back or kept. Only the first of the agent's
278
+ own is taken, so the writer never puts a second one with a copy. A
279
+ copy given when a writer is opened is made plain data before it is
280
+ checked, so what is handed back is what was checked; one given already
281
+ holding two of the agent's own is handed back with both, and the
282
+ first is the one the writer goes on handing back. A copy that cannot
283
+ be made plain data is refused when the writer is opened. A copy holds four
284
+ acknowledgements at most; the writer's own is always among them, and
285
+ where the copy already holds four, the last of the others gives way. What is not a cancellation record at all (a record with a
286
+ member added to it, for example) is refused and stops nothing. What
287
+ is handed to `add` is read once, member by member, so a member whose
288
+ value changes from one reading to the next cannot make the writer
289
+ read two different entries. A check may be handed 16 cancellations at
290
+ most. The writer holds, in this order: its own slip's cancellations
291
+ that the book does not hold; acknowledgements that wait, in the order
292
+ in which they began to wait, so that the newest gives way first; then
293
+ the other copies given at opening, which give way. Where it already holds
294
+ 16 of the first two kinds, a further cancellation of its slip that
295
+ cannot be written into the book still stops that writer, and is not
296
+ kept or handed back; the error says so, also where the clock fails.
297
+ An acknowledgement that begins to wait while the writer holds 16 of
298
+ its own slip's cancellations is not handed back, and a writer opened
299
+ again signs a second one; both are genuine. A copy given at opening
300
+ that carries a waiting acknowledgement counts with the waiting ones. A
301
+ copy that gives way is no longer handed to the writer's own check: one
302
+ that carried a time-stamp the book's line lacks then no longer marks
303
+ the stubs it marked, in the writer's answer. Whoever handed it over
304
+ keeps it, and a check of the book with it still marks them. What is
305
+ handed to `add` wrapped in a Proxy is read once, as plain data, like
306
+ anything else: each member and each place is read once and copied as
307
+ it is read, and a gap or a faulty item in a list of time-stamps
308
+ leaves a sound one beside it as it is. The copy is measured by the
309
+ length its text would have: each of the three members of a
310
+ cancellation may be as long as a line, and all the other members
311
+ together as long as one more. Past that, the entry is not written as
312
+ it was handed over and the rest of it is not read, but the
313
+ cancellation in it still stops the writer. So what is handed over
314
+ beside a cancellation cannot make the writer use memory or time out
315
+ of proportion. A list whose length is not a whole number is not plain
316
+ data, and anything but an object (a list, for one) is not written out
317
+ at all. Acknowledgements of other
318
+ agents that stay with a kept copy are not written into the book with
319
+ it: once the copy is written, the writer no longer hands them back.
320
+ Whoever handed them over keeps them.
321
+ - **Every line is tried before it joins the book.** The stub writer
322
+ reads each new line on a reader split off the book's own, which takes
323
+ the book's place only if the line is written. So an error part of the
324
+ way through a call (a clock that fails, an action that fails, an entry
325
+ that does not fit) leaves the writer's view of its book exact: a test
326
+ compares it with a whole check. An entry that does not fit costs one
327
+ line's check, not a reading of the whole book.
328
+ - **What the stub writer is told to trust** is read once, when it is
329
+ opened, as a whole check reads it, and copied where it is plain data;
330
+ the passkeys it trusts (`issuerKeys`) as well. The same holds for a
331
+ checker that is carried on. An option that is an object of a class,
332
+ or a function, is kept as it was handed over: a check refuses or
333
+ ignores it as a whole check does, and it is not fixed. So is a list
334
+ whose length is not a whole number. So is a value that cannot even be
335
+ looked into (a revoked Proxy); one of those given as an option is a
336
+ problem with the whole check (`check-failed`), and the stub writer
337
+ refuses it when it is opened. A value more than 16 levels down in the
338
+ options cannot be read: no option nests so deep, and nothing past
339
+ that depth is kept as it was handed over. A value met twice is copied
340
+ once, so options that share values, or that hold themselves, cost no
341
+ more to copy than they hold values. The list of signing methods to
342
+ treat as not built in is read with every line, so one that cannot be
343
+ read is a problem with the whole check from its start. A whole check reads its options through the same fixed copy,
344
+ so the two cannot read them differently: a list is read as the plain
345
+ list of what it holds, whatever kind of list it is. An option, a
346
+ member or a place in a list that cannot be read fails, with the same
347
+ error, wherever a check reads it, and nowhere else; the stub writer
348
+ refuses an option that cannot be read at all when it is opened.
349
+ A gap in a list stays a gap, and a gap in the list of blocks or of a
350
+ copy's time-stamps is refused. Lists are read place by place, never
351
+ through a list's own way of walking through itself, and a very long
352
+ list with few items in it costs little. The list of blocks holds at
353
+ most 100,000. A copy of a cancellation given at opening is copied as
354
+ plain data, whatever kind of object it is, so the writer never
355
+ changes the caller's own object.
356
+ - **A finding about a period may be given for another chain's stub.** A
357
+ period goes by the times the stubs state. A helper's stub written
358
+ later and dated earlier can put an earlier, honest stub of the agent
359
+ over the limit, and that stub is then the one marked. The record still
360
+ shows the limit was passed, and by which stubs together.
361
+ - **The shared list is a first draft.** A name on it means what the list
362
+ says only if those who use it agree.
363
+
364
+ ## 5. The chain and the book
365
+
366
+ **Protects.** That stubs under one slip are in an unbroken order: each
367
+ names the one before, and each is numbered. A stub cannot be changed,
368
+ removed from the middle or moved without the break showing.
369
+
370
+ **From whom.** A2 (cannot edit, reorder or remove from the middle
371
+ unnoticed).
372
+
373
+ **Does not protect, by itself.**
374
+
375
+ - **A block that is not part of the chain.** A block time-stamp comes
376
+ with the header of its block, and the checker cannot tell a real block
377
+ from a made-up one. It counts only for a block whose fingerprint the
378
+ person checking named, having compared it with sources they trust.
379
+ Naming a block that someone else supplied, unchecked, is trusting them.
380
+ - **A block's time is loose.** It is right only to within about two
381
+ hours. The looseness is always taken against whoever is being checked:
382
+ for a seal a block time-stamp counts as "existed by the stated time and
383
+ two hours"; for a cancellation it counts from two hours before the
384
+ stated time, so that no stub made after the person cancelled escapes,
385
+ but not from before the date the person signed in the cancellation
386
+ itself.
387
+ A proof is complete only hours after it is asked for. A block that
388
+ states a time more than two hours behind the true time, which the
389
+ chain's rules allow in rare cases, would make an honest seal read as
390
+ dated after its time-stamp.
391
+ - **Checked once against real proofs, not in the tests.** The tests use
392
+ made-up blocks. On 5 October 2026 two complete proofs that others had
393
+ published, one made by hand from a transaction and one made by public
394
+ calendar services, were checked with this reader against the headers
395
+ of the real blocks they name, taken from the whole chain of headers
396
+ and checked from its first block: each led to its blocks (five in
397
+ all), and each was refused with another block's header or with its
398
+ file changed by one bit. Older published sample proofs of the format
399
+ were read with this reader too: the incomplete ones are read to their
400
+ end; the complete ones among them are old, and use a step this reader
401
+ does not
402
+ accept.
403
+ - **Removing the latest stubs.** In a book with no seal, or after its
404
+ last seal, whoever holds the book can remove the latest stubs under any
405
+ slip or any pass, or a slip or a pass together with all its stubs, and
406
+ what is left still checks. This can hide the very stub that shows the agent outside its
407
+ slip. A seal closes this for everything before it (section 6a). After
408
+ the last seal, only a copy of a top fingerprint, with its number of
409
+ entries, held by someone else would show it.
410
+ - **Writing a different history with the agent's keys.** A1, A3 or A5
411
+ can sign a second, different chain under the same slip. Countersigned
412
+ stubs resist this, because the service's keys are needed. One-sided
413
+ stubs do not.
414
+ - **When.** Without an outside time-stamp from a service the checker
415
+ trusts, a whole book could have been written yesterday. Section 6a.
416
+
417
+ ## 6. The tree and the one-page proof
418
+
419
+ **Protects.** That one entry is part of a book with a given top
420
+ fingerprint, without showing the rest of the book. Built exactly as RFC
421
+ 6962 (Certificate Transparency), section 2.1, sets out.
422
+
423
+ **From whom.** A2 and A6 (cannot make a proof for an entry that is not in
424
+ the book; cannot change an entry and keep the proof).
425
+
426
+ **Does not protect.**
427
+
428
+ - The top fingerprint itself. A proof is worth as much as the checker's
429
+ reason to trust the top fingerprint: a seal with a time-stamp that
430
+ comes with the Show (section 6a), or their own earlier copy.
431
+ - The number of entries. The top fingerprint does not by itself fix how
432
+ many entries the book holds. Keep the number with every copy of a top
433
+ fingerprint.
434
+ - Limits. One page cannot show whether a limit was kept: that needs every
435
+ stub under the slip.
436
+
437
+ ## 6a. The Seal and the outside time-stamp
438
+
439
+ **Protects.** That the entries before a seal are exactly the entries the
440
+ recorder sealed: none changed, added or removed. With a time-stamp from a
441
+ service the checker trusts: that those entries existed by the time the
442
+ service states, whatever the recorder says later.
443
+
444
+ **From whom.** A1 and A2 can no longer remove the latest stubs under a
445
+ slip, or a slip with its stubs, from before a seal: the seal after them
446
+ no longer fits. They cannot back-date an entry into a sealed part, nor
447
+ date an entry, a countersignature or an approval later than the
448
+ time-stamp that covers it, in a book or in a Show under a seal (to
449
+ within 5 minutes for a time-stamp from a service, and to within 2 hours
450
+ and 5 minutes for a block time-stamp). A6 cannot make a
451
+ seal: it needs the recorder's three keys. A8 must break Ed25519, ML-DSA-87
452
+ and SLH-DSA together to forge a seal; the third rests only on fingerprint
453
+ functions. Nobody can move a time-stamp to another seal: it is made over
454
+ the seal's fingerprint.
455
+
456
+ A block time-stamp is a second witness of the time, which rests on no
457
+ signature at all: only on SHA-256, and on the block being part of a
458
+ public blockchain that the person checking named. A8 gains nothing
459
+ against it by breaking every signing method of today.
460
+
461
+ **How.** The seal names the number of entries before it and their top
462
+ fingerprint, and the seal before it. A checker that holds the book works
463
+ both out again. The time-stamp follows RFC 3161 and is checked offline:
464
+ its statement, the signed attributes that name the statement, the
465
+ signature, and the time against the certificate's dates. The checker
466
+ trusts a service only by the fingerprint of its certificate, which the
467
+ person checking gives.
468
+
469
+ **Does not protect.**
470
+
471
+ - **The end of the book.** The last seal, with everything after it, can
472
+ be removed, and what is left still checks. Only a copy of that seal, or
473
+ of its top fingerprint and number of entries, held by someone else
474
+ shows it. A public place where seals are kept would close this; it is
475
+ not built.
476
+ - **Entries after the last time-stamp.** They are not time-stamped.
477
+ - **A recorder who seals a false book.** A1 holding the agent's keys and
478
+ the recorder's keys can write another history and seal it. A time-stamp
479
+ then proves only when that was done: a book sealed long after the times
480
+ its stubs claim deserves doubt. Countersignatures and the other side's
481
+ own book are what tie a history to someone else.
482
+ - **A time-stamp service that lies, or whose key is stolen.** Its time is
483
+ then wrong. Time-stamps from several services, which a seal may carry,
484
+ limit the harm.
485
+ - **A8 against the time-stamp.** Time-stamp services sign with methods of
486
+ today's kind. A forger with a large quantum computer could make a
487
+ time-stamp. The seal's own signatures would still have to be forged.
488
+ - **A certificate is not judged.** The checker does not follow a chain of
489
+ certificates, does not ask whether a certificate was withdrawn, and
490
+ does not read what a certificate says its key is for. It checks that
491
+ the stated time lies within the certificate's dates, and leaves the
492
+ rest to the person who chose to trust it.
493
+ - **A browser.** No browser offers SLH-DSA or ML-DSA to a page yet. A
494
+ checker there reports a seal as not fully checked, never as a pass.
495
+ - **A few bytes of a time-stamp's wrapper** are not covered by the
496
+ service's signature (the list of fingerprint methods, and the lines
497
+ that name the certificate by its issuer). Changing them changes nothing
498
+ the time-stamp says: which certificate signed is taken from the signed
499
+ part, and every part must still be well formed.
500
+ - **A time-stamp from a service the checker did not name** is compared
501
+ with nothing. Anyone can make one, so it must not be able to make a
502
+ sound record fail, any more than pass.
503
+ - **A seal shown as a single page of a Show** cannot be compared with the
504
+ entries before it. The page says so, and its time-stamp is credited to
505
+ no other page. Its dates are still held against the pages that come
506
+ before it in the book, and it is held to the dates and the chain of
507
+ the other seals of the Show. Where they do not fit, the finding is
508
+ given for the seal and never for the page before it: the seal may not
509
+ belong to the book at that place, and single pages cannot show which
510
+ of the two is at fault. A Show made under a seal is the form that
511
+ proves a time.
512
+ - **The time-stamps beside the last seal.** Nothing fixes the
513
+ time-stamps beside the last seal of a book, or beside the seal that
514
+ comes with a Show: whoever hands the record over can put a later
515
+ time-stamp in the place of an earlier one. A later time-stamp shows
516
+ less, never more, and the entries are still held against the seal's
517
+ own date, so the gain is at most 300 seconds.
518
+ - **A Show under a later seal.** Whoever hands over a Show chooses its
519
+ pages and its seal. Where a page is dated after the time-stamp of a
520
+ seal that comes after it in the book, that is reported only if the
521
+ seal is among the pages, and the seal is the page reported. With that
522
+ seal left out, the Show passes where the whole book fails. Only the
523
+ whole book shows it in every case. The same holds for a unique number
524
+ used twice: the seal that comes with a Show is held to the pages, and
525
+ a record left out of the pages cannot be compared.
526
+ - **A seal dated before a time-stamp that it covers.** A seal covers
527
+ the lines of the seals before it, time-stamps included. One dated more
528
+ than 300 seconds before the latest time a service gave any of them is
529
+ reported: it cannot have been made by then. In a Show this is seen
530
+ only for seals among the pages.
531
+ - **What a Show cannot show about an earlier seal.** The two rules that
532
+ rest on a seal earlier in the book (the one above and the one below)
533
+ are applied in a Show only for seals among its pages. With such a seal
534
+ left out, a Show may pass where the whole book fails; it may show its
535
+ pages as having existed earlier than the whole book shows; and, with a
536
+ block that states a time far behind the true time, it may fail where
537
+ the whole book passes. Only the whole book shows it in every case.
538
+ - **A block that states a time before an earlier seal's time-stamp.** A
539
+ later seal covers the earlier seal's line, time-stamp included, so it
540
+ cannot have existed before the time a service gave the earlier seal.
541
+ A block time-stamp beside the later seal that states an earlier time,
542
+ even with its two hours, is set aside, and the checker says so.
543
+ Without this, such a block (the chain's rules allow one in rare cases)
544
+ would show entries to have existed earlier than they did, and a stub
545
+ made after a cancellation would be excused.
546
+ - **Two times of an entry are kept apart.** The time by which a later
547
+ seal shows that an entry existed (`existedBy`) is one thing. The time
548
+ that a seal's or a cancellation's own time-stamps give it
549
+ (`stampedAt`) is another: a cancellation does not count from the time
550
+ of a seal after it, and is never shown as if it did. A seal or a
551
+ cancellation that did not pass its check shows no time of its own.
552
+ - **A time-stamp on a cancellation this device could not confirm.**
553
+ Where the device lacks the passkey's signing method, no date is
554
+ reported against the cancellation's time-stamp, as for a seal. The
555
+ record is then not a pass in any case.
556
+ - **Two time-stamps that do not agree.** Every counted time-stamp of a
557
+ seal is taken, and the earliest shows when its entries existed. One
558
+ case is set apart: beside a time-stamp from a service, a block
559
+ time-stamp that states a time more than two hours before the seal's
560
+ own date is set aside, and does not make the seal fail. A block may
561
+ state a time far behind the true time. The checker says that the two
562
+ do not agree. The other reading is that the seal existed before the
563
+ date it gives. The same holds for a cancellation: it is never taken to
564
+ have been made before the date the person signed in it, so nobody can
565
+ move a cancellation back in time by having it put into a block before
566
+ that date.
567
+ - **Cost.** A time-stamp is read only if the seal's own signatures did
568
+ not fail, only the one certificate it names is tried, and an RSA key
569
+ must have a small public number, so that a small file cannot cost much
570
+ work.
571
+
572
+ **Knowing that a block is part of the chain.** The person checking can
573
+ name the blocks they trust, or hand the checker a chain of block headers
574
+ (`--headers`), which `provared-headers` fetches from Bitcoin nodes the
575
+ person names.
576
+
577
+ - **Protects.** Every header is checked on the device, from the chain's
578
+ first block, by the rules every node applies to headers: the link to
579
+ the block before, the work, the difficulty rule, the rules on times,
580
+ and the lowest version a block may have after the upgrades of 2013 and
581
+ 2015. The chain must hold ten blocks known to be part of it, at their
582
+ places, and must reach the last of them (block 969,696). A chain that
583
+ branches off before that block cannot hold them. After it, no target
584
+ may be more than four times easier than that block's, a rule of this
585
+ checker's own: the real chain's difficulty has never eased by more
586
+ than one and a half times at one change. So every block of a branch made after the last
587
+ known block carries at least a quarter of the work a real block
588
+ carried in October 2026, and a block counts only with at least six
589
+ blocks after it. When headers are fetched, a second node, on a network
590
+ apart from every node that gave headers, must hand back the latest six
591
+ blocks itself, checked on a copy of the chain; a branch near the end is
592
+ taken on only if it carries more work; and a chain file is never
593
+ written shorter than it was, or half written. So a node can refuse,
594
+ fall silent or hold back the newest blocks, but cannot have a false
595
+ header kept.
596
+ - **Does not protect.**
597
+ - The ten known blocks are written into the library. They were read on
598
+ 5 October 2026 from the whole chain, checked by these rules from the
599
+ first block, which a second node on another network agreed with.
600
+ Whoever trusts the library trusts them. A later release may add newer
601
+ ones.
602
+ - Someone with mining equipment could make a branch of their own after
603
+ the last known block, with a block that holds what they choose. The
604
+ rules on difficulty let them push the dates of a branch forward to
605
+ ease its targets at each change; the rule above stops that at four
606
+ times. A false block with six blocks after it then costs at least the
607
+ work of about two real blocks of October 2026. A chain file that
608
+ someone else hands over could hold such a branch: a chain fetched
609
+ from nodes the person chooses, with a second node agreeing, could
610
+ not, unless every node named was in on it. Fetch your own, or name
611
+ the blocks you trust.
612
+ - If every node named holds back the newest blocks, the chain ends
613
+ early, and a recent block is not found. Nothing false is counted.
614
+ - The nodes named see the device's address, and that headers were
615
+ asked for. A node named by its name is looked up by the device's own
616
+ name service. The connection is not encrypted; nothing secret is
617
+ sent.
618
+ - A node is given fifteen minutes at most, and must answer what is
619
+ asked within a minute; its own messages do not keep a session open.
620
+ - A device whose clock is far behind refuses the newest headers, whose
621
+ times are then more than two hours ahead of it.
622
+ - The checking page cannot yet take a chain of headers.
623
+
624
+ ## 6b. Cancelling, vouching and withdrawing
625
+
626
+ **Protects.** That a slip was ended by the person who signed it, and
627
+ from when. That a name in a record had an organisation standing behind
628
+ it, which the person checking chose to trust. That such a statement was
629
+ ended only by the organisation that made it.
630
+
631
+ **From whom.** A3 and A6 cannot cancel a slip, or undo a cancellation:
632
+ only the passkey that signed the slip can cancel it. A3 cannot escape a
633
+ time-stamped cancellation by writing an earlier time into a stub: a stub
634
+ counts as earlier only if an outside time-stamp shows it. Where the
635
+ person cancelled more than once, A6 gains nothing by the order the
636
+ cancellations stand in: every one counts, and the earliest time-stamped
637
+ time is used. A6 cannot make a vouching record count: it must be signed
638
+ by an organisation the checker named. Nobody but that organisation can
639
+ withdraw it. A vouching record that has run out does not stand behind a
640
+ slip whose time runs past it. Where the person kept their own copy of a
641
+ cancellation, with its time-stamp, A6 can neither make it disappear from
642
+ a check nor move it later in time: the checker takes the copy beside the
643
+ book.
644
+
645
+ **Does not protect.**
646
+
647
+ - **A cancellation the recorder leaves out, where the person kept no
648
+ copy.** Whoever keeps the book can keep a cancellation out of it. The
649
+ person should keep their own copy, with its time-stamp, and hand it to
650
+ the checker beside the book: it then counts as if it were there. A copy
651
+ with no time-stamp from a service the reader trusts cannot be placed in
652
+ time: it stops the agent's software that is handed it, and marks no
653
+ stub.
654
+ - **A cancellation with no time-stamp.** Only its place in the book says
655
+ when it took effect, and the recorder chose that place.
656
+ - **A cancellation the person keeps back.** A cancellation shows when
657
+ the person signed it and had it time-stamped. It does not show that
658
+ the agent, or whoever keeps the book, was told. A person can sign and
659
+ time-stamp a cancellation, tell nobody, and hand it over later: every
660
+ stub made in between is then reported as after the cancellation,
661
+ though the check before acting allowed each. Where the book does not
662
+ hold a cancellation that is handed over beside it, the checker says
663
+ that the keeper left it out or was never given it. It cannot show
664
+ which, unless the person was given an acknowledgement (below).
665
+ - **An acknowledgement is the agent's side's own word.** It shows that
666
+ the agent's software stated, with the agent's keys, that it was handed
667
+ the cancellation at a time. Handed over with the person's copy, it
668
+ tells the two cases apart: a stub of that agent dated after it was, by
669
+ the agent's own dates, made after the agent's side was told, and is
670
+ reported in words of its own. So is a pass that the agent handed on
671
+ after it was told, every pass handed on from it, and every stub under
672
+ them: an agent that was told cannot go on through a helper. It does
673
+ not show when the person cancelled, nor that a helper agent which held
674
+ its pass before then was told. An agent that writes earlier dates into
675
+ its stubs escapes this rule, and is caught only by the time-stamp
676
+ rule, which is applied first and whose findings are kept. Nothing
677
+ obliges an agent's side to acknowledge; this library's stub writer
678
+ does, for every cancellation of its slip that is handed to `add`, and
679
+ never dates an acknowledgement before its own last stub or a pass it
680
+ handed on. An acknowledgement that is dated ahead of the clock for
681
+ that reason follows its cancellation into the book once the clock has
682
+ reached its date. A writer that
683
+ was opened with keys that are not the agent's hands back no
684
+ acknowledgement: one it signed would not check.
685
+ - **An acknowledgement that does not check**, handed over with the
686
+ person's copy, is a problem with the whole check and is never set
687
+ aside silently. The cancellation itself is still used: the agent's
688
+ side cannot spoil the person's copy by handing them an acknowledgement
689
+ that does not check. An acknowledgement in a book does not pass once
690
+ the cancellation it names has failed its check, even where that shows
691
+ only later in the book.
692
+ - **A time-stamp on a cancellation that is swapped for a later one.**
693
+ The time-stamps stand beside the cancellation, not inside what the
694
+ passkey signed. Whoever keeps the book can put a later time-stamp from
695
+ the same service in the place of the person's own; a stub sealed in
696
+ between then counts as earlier. No check of the book alone can show the
697
+ swap. The checker points out a time-stamp dated more than 300 seconds
698
+ after the cancellation's own date. The person's own copy, with its
699
+ time-stamp, handed to the checker beside the book, overrules it. A
700
+ later time-stamp put beside an earlier one, in the book or in the
701
+ person's copy, changes nothing: the earliest that any counted
702
+ time-stamp gives is the time used.
703
+ - **A slip written late, with early dates.** A slip's times are its
704
+ issuer's own word. A slip written after a vouching record ran out, with
705
+ times inside the old window, is caught only where an outside
706
+ time-stamp shows when it was written.
707
+ - **Single pages.** A Show cannot show that a slip was not cancelled, or
708
+ a vouching record not withdrawn, on a page that is not shown; the
709
+ checker says so with every Show.
710
+ - **A withdrawal has only its place in the book.** A slip that sits
711
+ before the withdrawal keeps the vouching, even if it was signed after
712
+ the organisation decided to withdraw. Seals and time-stamps bound how
713
+ far a book can be rearranged.
714
+ - **A stub made honestly just before a cancellation**, and not yet under
715
+ a time-stamped seal, is reported as not shown to have been made in
716
+ time. That is what the record can show. A recorder that seals often
717
+ keeps it rare.
718
+ - **What the organisation did to check.** A vouching record shows that
719
+ the organisation stood behind a name. It does not show how well it
720
+ checked, nor that the organisation is who its own name says.
721
+ - **The agent's software.** The fingerprints in a slip are a statement
722
+ of what the person approved. Nothing shows which program signed with
723
+ the agent's keys.
724
+
725
+ ## 6c. Covered fields
726
+
727
+ **Protects.** That a slip can be shown with its names and its purpose
728
+ hidden, while its signature, its place in the book and every comparison
729
+ of stubs with it still check. That a revealed field is exactly the field
730
+ that was signed: nobody can reveal a different name or purpose.
731
+
732
+ **From whom.** A reader who is handed a slip without its disclosures
733
+ learns no covered name and no purpose: each is replaced, in what was
734
+ signed, by the fingerprint of the field mixed with 128 random bits, so it
735
+ cannot be guessed. A2 and A6 cannot make a disclosure for a value that
736
+ was not signed. A disclosure cannot be moved to another slip. Nobody can
737
+ write a slip that shows one reader different limits, conditions,
738
+ actions, services or keys from another: only a name or the purpose can
739
+ be covered, an item of a list never, and a field is absent only where
740
+ exactly its one fingerprint stands in its place.
741
+
742
+ **How.** The method is the standard "Selective Disclosure for JSON Web
743
+ Tokens" (RFC 9901), with its own checking steps: a fingerprint may appear
744
+ once; a disclosure must belong to the record; a revealed name may not
745
+ replace a field that is there. The standard's worked example is a test.
746
+
747
+ **Does not protect.**
748
+
749
+ - **Only a slip's names and purpose can be covered.** The actions, the
750
+ limits, the keys and the times cannot: a checker needs them. Stubs and
751
+ other records cannot hold covered fields in this draft, so the names of
752
+ documents in a stub are visible to whoever holds the stub.
753
+ - **That a field is covered is visible.** A reader sees that something is
754
+ hidden, and how many fields.
755
+ - **A disclosure, once handed over, cannot be taken back.**
756
+ - **Whoever keeps the disclosures can read the fields.** Covering limits
757
+ what a reader of a record learns, not what its keeper knows.
758
+ - **A covered name cannot be vouched for** to a reader who cannot see it.
759
+ - **A covered name may be visible in another record.** A vouching record
760
+ states the name it vouches for, and a service's terms and refusals
761
+ state the service's name. Covering a name in a slip does not cover it
762
+ there.
763
+ - **A disclosure that does not fit.** The signer of a slip can cover a
764
+ name with a value that a slip may not hold. The slip is sound while the
765
+ name stays covered. Handed the disclosure, the checker refuses the
766
+ disclosure, says so, and checks the slip as before: what a slip is does
767
+ not depend on what is handed over with it. The check as a whole is then
768
+ not a pass, and the reader should check again without that disclosure.
769
+ - **A slip uses less than the standard allows.** No covered item of a
770
+ list, no decoy fingerprints, disclosures in the canonical form only.
771
+ Software written for the standard alone must be told so.
772
+ - **The person signs the covered form.** What they are shown on the
773
+ signing page is up to that page: A9 still wins.
774
+
775
+ ## 6d. Passing a slip on
776
+
777
+ **Protects.** That a helper agent acted under a pass signed by the agent
778
+ that held the permission, that the slip allowed passing on, and that
779
+ everything the helper did is compared with the slip the person signed.
780
+
781
+ **From whom.** A3 cannot widen its permission by passing it on: a
782
+ helper's stubs are compared with the slip itself, and the slip's totals
783
+ take in the agent and every helper together. A helper cannot widen its
784
+ own by passing on either: a stub is compared with every pass above its
785
+ own, and the totals of each take in what is done further down. A stub
786
+ in one chain, dated later, cannot empty a limit "within a period" for
787
+ another chain: periods go by the times the stubs state, wherever the
788
+ stubs stand in the book. A helper cannot act under
789
+ another slip's pass, nor write into the first agent's chain. A6 cannot
790
+ make a pass: it needs the keys of the agent that passes on.
791
+
792
+ **Does not protect.**
793
+
794
+ - **An agent that hands over its own keys** instead of writing a pass.
795
+ The helper's actions then look like the agent's own.
796
+ - **Who the helper is.** Its name in a pass is a label, unless a
797
+ vouching record stands behind it.
798
+ - **A pass the slip does not allow** is not refused: it is reported, with
799
+ every stub under it, as outside the slip. The record is still sound.
800
+ Only an eleventh pass in a row, which no slip can allow, is refused.
801
+
802
+ ## 7. The checker and the checking page
803
+
804
+ **Protects.** A7 cannot crash the checker, make it run a script, or make
805
+ it show a pass for a record that does not check.
806
+
807
+ **How.**
808
+
809
+ - A failed check is a normal answer with a named reason, never a crash.
810
+ If the checker itself meets something it did not expect, that too is
811
+ reported as a problem, never as a pass.
812
+ - What an entry says is shown only if the entry passed its check. Text
813
+ from a record is shown with control characters, characters that cannot
814
+ be seen (every character that Unicode says is left out when text is
815
+ drawn, and the blank Braille pattern), and characters that change the
816
+ direction of text, replaced by a visible mark. Runs of spaces are
817
+ shown as one. A name or a purpose is shown inside quotation marks, and
818
+ a quotation mark inside it as an apostrophe, so that a reader can see
819
+ where the record's words end and the checker's begin. No word a record contains is copied into a message
820
+ about a problem.
821
+ - A flood of empty lines is refused as soon as there are too many, before
822
+ any is read.
823
+ - Every field of a record is treated as untrusted text. The checking
824
+ page writes it as text and never as markup.
825
+ - Every member name in a record is treated as a plain name. A member
826
+ named `__proto__` is a member like any other: it is refused where it
827
+ is unknown, and nothing is inherited from it. What is looked up by a
828
+ name that came from a record, such as a service's id, finds only what
829
+ the checker itself put there.
830
+ - "Within its slip" is said only if every stub and every pass was
831
+ compared on this device.
832
+ - Records over a fixed size, or nested too deeply, are refused.
833
+ - The content of a record must be written in one canonical form (RFC
834
+ 8785). A record with a repeated field name, stray spaces or an unusual
835
+ number form is refused, so two checkers cannot read the same record in
836
+ two ways.
837
+ - The checker makes no network request. Nobody learns which record was
838
+ checked. Only `provared-headers`, which the person runs, connects to
839
+ anything: to the Bitcoin nodes the person names, for block headers.
840
+ It asks for every header from the first block onwards, so a node does
841
+ not learn which blocks matter to the person.
842
+ - What the person hands the checking page beside a record (their own
843
+ copies of cancellations, disclosures for covered fields, the blocks
844
+ and fingerprints they trust) is read in the browser and sent nowhere.
845
+ A file that is not JSON, or a line that is not a fingerprint, stops
846
+ the check and says so: it is never set aside silently. The sample
847
+ record is checked without the files handed over.
848
+ - The checker depends on no outside code. It uses only the cryptography
849
+ built into the browser or Node.js.
850
+ - **The checking page as one file** (`tools/make-single-page.mjs`) holds
851
+ the page, its style, the checker and the sample record, copied in
852
+ unchanged; a test compares each with the file it was copied from. Its
853
+ content security policy lets nothing be loaded from anywhere, and lets
854
+ only the one script and the one style in the file run, named by their
855
+ fingerprints. So the file can make no request, whatever a record
856
+ holds. Whoever is handed the file should compare its SHA-256
857
+ fingerprint with one obtained from a place they trust: a changed copy
858
+ is a changed checker.
859
+ - **A checker that is carried on** (`openChecker`, and the stub writer)
860
+ reads a book once and then takes more lines without reading the
861
+ earlier ones again. There is one way of reading a line, and a whole
862
+ check is: start, read every line, give the answer. So a book that is
863
+ carried on gets the answer a whole check gives. A test compares the
864
+ two after every line of a book that holds every kind of entry, sound
865
+ and unsound. What can be found only once every stub has been read (a
866
+ limit "in any period", what a cancellation handed over beside the
867
+ book shows) is worked out afresh for each answer and never written
868
+ into what the checker keeps. Each answer handed out is a copy, and
869
+ what the checker is told to trust is copied when it is opened, so
870
+ nothing done outside changes what it keeps.
871
+ - **Trying a line.** The stub writer tries each new line on a reader
872
+ split off the book's own. For a stub that reader is a light copy: a
873
+ stub is the one kind of entry that changes nothing read before it, and
874
+ the light copy refuses any other kind. For an entry that someone else
875
+ made it is a full copy. If the line is not written after all (it does
876
+ not fit, the action fails, the clock fails), that reader is thrown
877
+ away, and the book's own reader is as it was: a test compares it with
878
+ a whole check after every try. An entry that does not fit costs one
879
+ line's check, never a reading of the whole book.
880
+
881
+ **Does not protect.**
882
+
883
+ - A checker run on a taken-over device.
884
+ - A checker that is itself altered. Use a copy you obtained from a place
885
+ you trust.
886
+ - A carried checker against a book that is changed behind it. It knows
887
+ the lines it was handed. If the text of the book is changed elsewhere
888
+ (by a second stub writer, or by hand), its answer is for the lines it
889
+ read. Check the whole book again where that may have happened.
890
+ - A book too large for memory. The checker reads the whole book at once.
891
+ A book of several hundred megabytes may be more than a browser or
892
+ Node.js will hold as one text; the check then fails, and says so.
893
+
894
+ ## 8. What is refused, and the test that proves it
895
+
896
+ Each row is one test in `test/refusals.test.mjs`, named by its code. A
897
+ further test reads this table and fails if a code here has no test.
898
+
899
+ | Code | What is refused or reported |
900
+ |---|---|
901
+ | `not-json` | A record that is not JSON text |
902
+ | `bad-envelope` | A record that is not laid out as a JSON Web Signature with exactly the expected members |
903
+ | `bad-base64url` | A value that is not strict base64url |
904
+ | `too-large` | A record over the size limit |
905
+ | `unknown-type` | A signature whose label is not one of the exact known labels |
906
+ | `bad-signatures-layout` | The wrong number or order of signatures, including a quantum-safe signature that has been stripped off |
907
+ | `payload-not-canonical` | Content that is not in the canonical form, including a repeated field name |
908
+ | `payload-type-mismatch` | Content of one kind under the label of another, for example a stub presented as a countersignature |
909
+ | `bad-field` | A missing, extra or wrongly typed field |
910
+ | `bad-key` | A public key that is not exactly of an accepted kind |
911
+ | `signature-invalid` | A signature that does not fit the key |
912
+ | `passkey-wrong-type` | A passkey answer that was made for creating a passkey, not for signing |
913
+ | `passkey-challenge-mismatch` | A passkey signature made for other content |
914
+ | `passkey-origin-mismatch` | A passkey used on a website other than the one the slip names |
915
+ | `passkey-rpid-mismatch` | A passkey that belongs to a website other than the one the slip names |
916
+ | `passkey-user-not-present` | A passkey signature with no sign that a person was there |
917
+ | `passkey-user-not-verified` | A passkey signature where the device did not confirm the person |
918
+ | `passkey-bad-data` | Passkey values that are cut short or malformed |
919
+ | `issuer-not-expected` | A slip signed by a key other than the ones the checker was told to expect |
920
+ | `slip-missing` | A stub whose slip is not earlier in the book |
921
+ | `slip-unusable` | A stub whose slip failed its own check |
922
+ | `chain-broken` | A stub that is missing, moved, repeated or changed |
923
+ | `time-went-backwards` | A stub dated before the stub ahead of it |
924
+ | `duplicate-id` | Two records with the same unique number |
925
+ | `duplicate-slip` | The same slip twice in one book |
926
+ | `countersignature-invalid` | A countersignature that does not fit the service's keys |
927
+ | `countersignature-wrong-stub` | A countersignature made for a different stub |
928
+ | `countersignature-not-possible` | A countersignature from a service for which the slip names no keys |
929
+ | `line-not-canonical` | A line of a book that is not in the canonical form |
930
+ | `unknown-entry` | A line of a book that is not one of the known kinds of entry |
931
+ | `approval-mismatch` | An approval put with a stub it was not given for: another action, amount, service, document or slip |
932
+ | `approval-reused` | One approval put with a second stub |
933
+ | `approval-invalid` | An approval that was not signed with the passkey the slip names, or whose passkey values do not check |
934
+ | `approval-not-found` | A stub that names an approval which is not with it |
935
+ | `approval-dated-after-stub` | An approval dated later than the stub that carries it |
936
+ | `terms-not-found` | A stub that relies on terms which are not earlier in the book |
937
+ | `terms-unusable` | A stub that relies on terms which failed their own check |
938
+ | `terms-mismatch` | A stub that relies on terms not signed with the keys the slip gives for the service it names |
939
+ | `pass-missing` | A stub, or a further pass, that relies on a pass which is not earlier in the book, or which failed its own check |
940
+ | `pass-mismatch` | A pass given under one slip, used under another |
941
+ | `pass-too-deep` | An eleventh pass in a row: a permission may be passed on at most ten times |
942
+ | `cover-invalid` | A disclosure of a covered field that does not belong to the record, was changed, is handed over twice, is not as its standard sets out, or is not in the canonical form; a covered item of a list in a slip; disclosures handed over with a page that is not a slip |
943
+ | `cancellation-invalid` | A cancellation that was not signed with the passkey the slip names |
944
+ | `cancellation-not-found` | An acknowledgement that names a cancellation which is not earlier in the book, did not pass its check, or cancels another slip |
945
+ | `acknowledgement-mismatch` | An acknowledgement handed over with the person's own copy of a cancellation that was given for another cancellation |
946
+ | `vouching-missing` | A withdrawal of a vouching record that is not earlier in the book |
947
+ | `seal-mismatch` | A seal that does not fit the entries before it: an entry was changed, added or removed after the seal was made. In a Show: a seal for another book, or for another length of this one |
948
+ | `seal-chain-broken` | A seal that does not name the seal before it: a seal is missing, moved or changed |
949
+ | `sealer-not-expected` | A seal signed with keys other than the ones the checker was told to expect |
950
+ | `dated-after-stamp` | An entry dated later than the outside time-stamp that covers it, or a seal dated later than its own time-stamp |
951
+ | `stamp-bad-data` | A time-stamp that is not laid out as its standard sets out |
952
+ | `stamp-wrong-data` | A time-stamp made for something other than this seal |
953
+ | `stamp-invalid` | A time-stamp whose signature does not check, or that is dated outside the time its service's certificate was in force |
954
+ | `headers-invalid` | A chain of block headers in which a header breaks a rule that every Bitcoin node applies, that does not hold the known blocks at their places, or that ends before the last of them (tested in `test/headers.test.mjs`) |
955
+ | `record-not-sound` | The check before acting: the record so far has a problem, or could not be checked on this device, so no action is allowed |
956
+ | `proof-invalid` | A one-page proof that does not lead to the top fingerprint |
957
+ | `root-mismatch` | A top fingerprint, or a number of entries, other than the one the checker was told to expect |
958
+ | `check-failed` | Anything the checker itself did not expect: reported as a problem, never as a pass |
959
+ | `action-not-allowed` | Reported, not refused: the agent did something the slip does not allow |
960
+ | `party-not-allowed` | Reported: the agent dealt with someone the slip does not name |
961
+ | `outside-valid-time` | Reported: the action is dated outside the slip's time |
962
+ | `amount-missing` | Reported: the slip sets a limit and the stub gives no amount in that unit |
963
+ | `over-limit` | Reported: the running total passes the slip's limit, and at which stub. In a Show: a single stub that passes the limit by itself |
964
+ | `over-each-limit` | Reported: one action is larger than the slip allows for a single action |
965
+ | `over-count-limit` | Reported: more actions of one kind than the slip allows |
966
+ | `over-period-limit` | Reported: the total, or the number of actions, within a period is more than the slip allows |
967
+ | `countersignature-missing` | Reported: the slip asks for the other side to countersign the action, and the stub is one-sided |
968
+ | `approval-missing` | Reported: the slip asks for the person's own approval of the action, and there is none |
969
+ | `prohibited` | Reported: an action of a kind the slip says the agent must never do |
970
+ | `pass-not-allowed` | Reported: the permission was passed on though the slip does not allow it, or more times than it allows; and every stub written under such a pass |
971
+ | `pass-wider` | Reported: a pass that hands on an action, or a time, that its writer does not itself hold |
972
+ | `after-cancellation` | Reported: a stub that comes after the person cancelled the slip, or that no outside time-stamp shows to have existed before a time-stamped cancellation |
973
+ | `outside-terms` | Reported: an action the service's terms for agents do not accept, or dated outside the time they were in force |
974
+
975
+ The last fifteen are what a sound record can show about the agent. They are
976
+ not faults in the record. The checker keeps three questions apart: "was a
977
+ problem found in the record?", "was every signature checked on this
978
+ device?" and "did the agent stay within its slip?". It calls a record
979
+ intact only when no problem was found and every signature was checked.
980
+
981
+ ## 9. When this document must be reviewed
982
+
983
+ - Before any change to a label, a field or the bytes that are signed.
984
+ - Before the first publication, when draft version 0 is frozen.
985
+ - When a public place for seals is added, when more fields may be
986
+ covered, when passing on changes, or when the way a time-stamp or a vouching
987
+ record is trusted changes.
988
+ - When a kind of limit, a condition, a rule of conduct or a shared action
989
+ is added, removed or changes its meaning.
990
+ - When a browser or Node.js changes how it offers ML-DSA or SLH-DSA.
991
+ - When the proof format of the block time-stamp changes, or a second
992
+ chain or a further kind of step is accepted.
993
+ - When a fault is found: the fault becomes a test and a row here. (Twenty
994
+ independent reviews from 3 to 5 October 2026 found the faults the
995
+ change log lists; each is now a test.)
996
+ - A gap between what this document claims and what the code does is a
997
+ defect of the highest priority.