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.
- package/CHANGELOG.md +1062 -0
- package/LICENSE +202 -0
- package/LICENSE-CC-BY-4.0.txt +396 -0
- package/README.md +689 -0
- package/bin/provared-check.mjs +565 -0
- package/bin/provared-headers.mjs +110 -0
- package/docs/threat-model.md +997 -0
- package/net/headers.js +403 -0
- package/package.json +57 -0
- package/page/check-page.js +162 -0
- package/page/index.html +47 -0
- package/page/render.js +530 -0
- package/page/style.css +150 -0
- package/samples/office-supplies.expected.json +82 -0
- package/samples/office-supplies.jsonl +10 -0
- package/samples/office-supplies.show.json +59 -0
- package/spec/provared-format.md +1672 -0
- package/src/actions.js +90 -0
- package/src/approval.js +73 -0
- package/src/blockstamp.js +198 -0
- package/src/book.js +2232 -0
- package/src/check.d.ts +21 -0
- package/src/check.js +15 -0
- package/src/compare.js +276 -0
- package/src/cover.js +198 -0
- package/src/der.js +192 -0
- package/src/encoding.js +286 -0
- package/src/fields.js +94 -0
- package/src/guard.js +171 -0
- package/src/headers.js +380 -0
- package/src/index.d.ts +2 -0
- package/src/index.js +37 -0
- package/src/jws.js +235 -0
- package/src/keys.js +149 -0
- package/src/pass.js +67 -0
- package/src/passkey-browser.d.ts +20 -0
- package/src/passkey-browser.js +171 -0
- package/src/recorder.js +1115 -0
- package/src/seal.js +133 -0
- package/src/service.js +124 -0
- package/src/signatures.js +147 -0
- package/src/slip.js +401 -0
- package/src/standing.js +181 -0
- package/src/stub.js +140 -0
- package/src/timestamp.js +351 -0
- package/src/tools.js +192 -0
- package/src/tree.js +143 -0
- package/src/types.d.ts +628 -0
- 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.
|