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,1672 @@
1
+ # The Provared format — draft version 0
2
+
3
+ A way to write down what an AI agent was allowed to do, and what it then
4
+ did, so that someone else can check it later with free tools.
5
+
6
+ *Evidence, not a verdict.* A record shows what was signed and by which
7
+ keys. People decide what it means.
8
+
9
+ ## 1. Status
10
+
11
+ This is **draft version 0**. Nothing in it is frozen. Every label below
12
+ ends in `v0` so that a frozen version can never be confused with this
13
+ draft. Do not rely on a draft record staying checkable.
14
+
15
+ Built in this draft: the Slip, with its limits, conditions and stated
16
+ rules; the Stub; the countersignature; the person's approval of one
17
+ action; a service's refusal and its terms for agents; the chain; the
18
+ book; the tree of fingerprints; the Seal, with outside time-stamps; the
19
+ one-page proof; cancelling a slip, and the agent's acknowledgement of a
20
+ cancellation; the block time-stamp; vouching for a name; covered fields
21
+ in a slip; and passing a slip on to a helper agent.
22
+
23
+ What is not in this draft is listed in section 12.
24
+
25
+ The words MUST, MUST NOT and MAY are used as RFC 2119 defines them.
26
+
27
+ ## 2. Words used
28
+
29
+ | Word | Meaning |
30
+ |---|---|
31
+ | Slip | A permission that a person signs with a passkey: which agent, which actions, what limits, with whom, from when until when, and why |
32
+ | Stub | A signed receipt for one action, pointing back to its slip |
33
+ | Countersignature | The other side's signed statement that the action happened with it |
34
+ | Approval | The person's own yes to one action, signed with the same passkey as the slip |
35
+ | Refusal | A service's signed statement that an agent asked for something and was refused |
36
+ | Terms | A service's signed statement of which actions it accepts from agents |
37
+ | Seal | The signed statement, by whoever keeps a book, of its top fingerprint and its number of entries at one moment |
38
+ | Recorder | Whoever keeps a book and seals it |
39
+ | Time-stamp | A signed statement by an outside service that a fingerprint existed by a time (RFC 3161); a block time-stamp is the like, from a block of a public blockchain (section 21.4) |
40
+ | Cancellation | The person's signed statement that a slip is ended early |
41
+ | Vouching record | An organisation's signed statement that a key belongs to a name |
42
+ | Withdrawal | The organisation's signed statement that a vouching record is ended |
43
+ | Pass | An agent's signed statement that it hands part of its permission to a helper agent |
44
+ | Chain | The stubs under one slip, each naming the one before |
45
+ | Book | A list of entries, one to a line: slips, stubs and the other records of this format |
46
+ | Top fingerprint | One fingerprint that stands for the whole book (the root of a Merkle tree) |
47
+ | Show | One or more entries of a book, each with proof that it is in the book |
48
+ | Issuer | The person who signs a slip |
49
+ | Agent | The software that acts, and signs stubs |
50
+ | Service | Whoever the agent deals with; it may countersign |
51
+ | Checker | Anyone who verifies a record, or the software they use |
52
+ | Fingerprint | The SHA-256 hash of some bytes, written in base64url (43 characters) |
53
+ | Passkey | A private key held in a phone, laptop or security key and unlocked by fingerprint, face or PIN (the W3C Web Authentication standard) |
54
+ | Hybrid | Two signatures on one record, one of today's kind and one quantum-safe; the record counts only if both check |
55
+
56
+ ## 3. Rules common to every record
57
+
58
+ ### 3.1 The signed envelope
59
+
60
+ Every record is a JSON Web Signature (RFC 7515) in the **general JSON
61
+ serialisation** (RFC 7515, section 7.2.1):
62
+
63
+ ```json
64
+ {
65
+ "payload": "<base64url of the content>",
66
+ "signatures": [
67
+ { "protected": "<base64url of the protected header>", "signature": "<base64url>" }
68
+ ]
69
+ }
70
+ ```
71
+
72
+ - The top level MUST hold exactly `payload` and `signatures`.
73
+ - Each entry of `signatures` MUST hold exactly `protected` and
74
+ `signature`, and, for a record signed with a passkey (a slip, an
75
+ approval or a cancellation), `header` (section 4.3).
76
+ - The bytes each signature covers are the JSON Web Signature signing
77
+ input (RFC 7515, section 5.1): the ASCII text of `protected`, a full
78
+ stop, and the ASCII text of `payload`.
79
+ - A record MUST NOT be larger than 65,536 characters, measured as the
80
+ lengths of its `payload` and of every text value in its signature
81
+ entries, added up. A writer MUST NOT make a larger record.
82
+
83
+ ### 3.2 Labels: the protected header
84
+
85
+ The protected header says what kind of record this is and which signing
86
+ method was used. Because it is part of the signed bytes, a signature made
87
+ for one kind of record can never pass as another kind.
88
+
89
+ In this draft the protected header, once decoded, MUST be **exactly** one
90
+ of these twenty-two texts, byte for byte. A checker compares the bytes and does
91
+ not interpret anything else.
92
+
93
+ | Record | Method | Protected header |
94
+ |---|---|---|
95
+ | Slip | Passkey | `{"typ":"vnd.provared.slip.v0+json","alg":"prova.red/webauthn/v0"}` |
96
+ | Stub | Ed25519 | `{"typ":"vnd.provared.stub.v0+json","alg":"Ed25519"}` |
97
+ | Stub | ML-DSA-87 | `{"typ":"vnd.provared.stub.v0+json","alg":"ML-DSA-87"}` |
98
+ | Countersignature | Ed25519 | `{"typ":"vnd.provared.countersignature.v0+json","alg":"Ed25519"}` |
99
+ | Countersignature | ML-DSA-87 | `{"typ":"vnd.provared.countersignature.v0+json","alg":"ML-DSA-87"}` |
100
+ | Approval | Passkey | `{"typ":"vnd.provared.approval.v0+json","alg":"prova.red/webauthn/v0"}` |
101
+ | Refusal | Ed25519 | `{"typ":"vnd.provared.refusal.v0+json","alg":"Ed25519"}` |
102
+ | Refusal | ML-DSA-87 | `{"typ":"vnd.provared.refusal.v0+json","alg":"ML-DSA-87"}` |
103
+ | Terms | Ed25519 | `{"typ":"vnd.provared.terms.v0+json","alg":"Ed25519"}` |
104
+ | Terms | ML-DSA-87 | `{"typ":"vnd.provared.terms.v0+json","alg":"ML-DSA-87"}` |
105
+ | Seal | Ed25519 | `{"typ":"vnd.provared.seal.v0+json","alg":"Ed25519"}` |
106
+ | Seal | ML-DSA-87 | `{"typ":"vnd.provared.seal.v0+json","alg":"ML-DSA-87"}` |
107
+ | Seal | SLH-DSA-SHA2-256s | `{"typ":"vnd.provared.seal.v0+json","alg":"SLH-DSA-SHA2-256s"}` |
108
+ | Cancellation | Passkey | `{"typ":"vnd.provared.cancellation.v0+json","alg":"prova.red/webauthn/v0"}` |
109
+ | Acknowledgement | Ed25519 | `{"typ":"vnd.provared.acknowledgement.v0+json","alg":"Ed25519"}` |
110
+ | Acknowledgement | ML-DSA-87 | `{"typ":"vnd.provared.acknowledgement.v0+json","alg":"ML-DSA-87"}` |
111
+ | Vouching record | Ed25519 | `{"typ":"vnd.provared.vouching.v0+json","alg":"Ed25519"}` |
112
+ | Vouching record | ML-DSA-87 | `{"typ":"vnd.provared.vouching.v0+json","alg":"ML-DSA-87"}` |
113
+ | Withdrawal | Ed25519 | `{"typ":"vnd.provared.withdrawal.v0+json","alg":"Ed25519"}` |
114
+ | Withdrawal | ML-DSA-87 | `{"typ":"vnd.provared.withdrawal.v0+json","alg":"ML-DSA-87"}` |
115
+ | Pass | Ed25519 | `{"typ":"vnd.provared.pass.v0+json","alg":"Ed25519"}` |
116
+ | Pass | ML-DSA-87 | `{"typ":"vnd.provared.pass.v0+json","alg":"ML-DSA-87"}` |
117
+
118
+ `typ` is the media type of the record (RFC 7515, section 4.1.9), used as
119
+ explicit typing (RFC 8725, section 3.11). `alg` names the signing method
120
+ (RFC 7515, section 4.1.1). `Ed25519` is the name RFC 9864 registers;
121
+ `ML-DSA-87` is the name RFC 9964 registers. `SLH-DSA-SHA2-256s` is the
122
+ name FIPS 205 gives that method; no registered name for it in this
123
+ envelope was found when this draft was written. `prova.red/webauthn/v0` is
124
+ not a registered name: it is a collision-resistant name under a domain
125
+ the format's author controls, which RFC 7515 section 4.1.1 allows.
126
+
127
+ ### 3.3 Base64url
128
+
129
+ Base64url is as RFC 4648, section 5, with no padding (RFC 7515, section
130
+ 2). A checker MUST refuse a value that holds any other character, has
131
+ padding, has an impossible length, or has stray bits set in its last
132
+ character.
133
+
134
+ ### 3.4 The content, and its canonical form
135
+
136
+ The content of a record (the decoded `payload`) is a JSON object in
137
+ UTF-8. It MUST be written in the JSON Canonicalization Scheme (RFC 8785):
138
+ no spaces or line breaks, the members of every object sorted by name, and
139
+ strings and numbers written in the one form that standard gives.
140
+
141
+ This draft narrows what the content may hold: objects, lists, strings,
142
+ whole numbers from 0 to 9,007,199,254,740,991, and nothing else. There
143
+ are no fractions, no negative numbers, no `null`, no `true` or `false`.
144
+ Strings MUST be well-formed Unicode. Nesting MUST NOT go deeper than 8
145
+ levels.
146
+
147
+ A checker MUST read the content, write it again in the canonical form,
148
+ and refuse the record if the two differ by a single byte. This refuses a
149
+ repeated member name, stray spaces and unusual number forms, so that two
150
+ checkers cannot read one record in two ways.
151
+
152
+ The signed bytes are always kept and checked exactly as they were signed.
153
+ The canonical form is a test the bytes must pass; it is never used to
154
+ rewrite them.
155
+
156
+ Every content object has a `type` member: `provared.slip.v0`,
157
+ `provared.stub.v0`, `provared.countersignature.v0`,
158
+ `provared.approval.v0`, `provared.refusal.v0`, `provared.terms.v0`,
159
+ `provared.seal.v0`, `provared.cancellation.v0`,
160
+ `provared.acknowledgement.v0`, `provared.vouching.v0`,
161
+ `provared.withdrawal.v0` or `provared.pass.v0`. It MUST match the `typ`
162
+ label of every signature on the record.
163
+
164
+ An object MUST hold exactly the members this document lists for it. A
165
+ checker MUST refuse an unknown member.
166
+
167
+ Wherever this document limits the length of a text, the length is counted
168
+ in characters (Unicode code points).
169
+
170
+ ### 3.5 Fingerprints
171
+
172
+ The **fingerprint of a record** is the SHA-256 hash (FIPS 180-4) of its
173
+ content bytes (the decoded `payload`), written in base64url. It is how a
174
+ stub names its slip, how a stub names the stub before it, and how a
175
+ countersignature names its stub.
176
+
177
+ ### 3.6 Times
178
+
179
+ A time is written as `YYYY-MM-DDTHH:MM:SSZ` (RFC 3339, in UTC, to the
180
+ second, with the letter Z). No other form is accepted.
181
+
182
+ ### 3.7 Unique numbers
183
+
184
+ An `id` is 16 random bytes written in base64url (22 characters).
185
+
186
+ ### 3.8 Keys
187
+
188
+ Public keys are written as JSON Web Keys (RFC 7517). Each MUST be exactly
189
+ one of these shapes, with no other member:
190
+
191
+ | Used by | Shape |
192
+ |---|---|
193
+ | Agent, service | `{"alg":"Ed25519","crv":"Ed25519","kty":"OKP","x":"…"}` (RFC 8037; `x` is 32 bytes) |
194
+ | Agent, service | `{"alg":"ML-DSA-87","kty":"AKP","pub":"…"}` (RFC 9964; `pub` is 2,592 bytes) |
195
+ | Recorder, third key | `{"alg":"SLH-DSA-SHA2-256s","kty":"AKP","pub":"…"}` (FIPS 205; `pub` is 64 bytes) |
196
+ | Issuer's passkey | `{"alg":"ES256","crv":"P-256","kty":"EC","x":"…","y":"…"}` (RFC 7518, section 6.2; 32 bytes each) |
197
+ | Issuer's passkey | `{"alg":"RS256","e":"AQAB","kty":"RSA","n":"…"}` (RFC 7518, section 6.3; `n` is 2,048 to 8,192 bits) |
198
+ | Issuer's passkey | `{"alg":"Ed25519","crv":"Ed25519","kty":"OKP","x":"…"}` |
199
+
200
+ A key is named for people by its **thumbprint**: the JSON Web Key
201
+ Thumbprint with SHA-256 (RFC 7638; for ML-DSA keys, RFC 9964 section 6).
202
+
203
+ ### 3.9 A key set: the hybrid
204
+
205
+ An agent or a service is known by a **key set**: a list of exactly two
206
+ keys, the Ed25519 key first and the ML-DSA-87 key second.
207
+
208
+ A stub, a countersignature, a refusal, a set of terms, a vouching record,
209
+ a withdrawal or a pass MUST carry exactly two signatures, in the same order: Ed25519 (RFC 8032), then ML-DSA-87 (FIPS 204, the plain
210
+ method with an empty context, as RFC 9964 section 5 requires). Both cover
211
+ the same content. The record counts as signed **only if both signatures
212
+ check**. The two signatures stand side by side as two entries of the
213
+ `signatures` list, as RFC 7515 already allows. Nothing is combined by a
214
+ method of this format's own.
215
+
216
+ Because the slip names both keys, taking the quantum-safe signature off a
217
+ stub does not leave a valid stub.
218
+
219
+ A checker on a device with no built-in ML-DSA MUST report that the
220
+ quantum-safe signature could not be checked, and MUST NOT report the
221
+ record as intact. An entry none of whose signatures the device could
222
+ check MUST NOT be treated as evidence: what it says is not shown as fact,
223
+ and it is not compared with its slip.
224
+
225
+ A recorder is known by a key set of exactly three keys: Ed25519,
226
+ ML-DSA-87, then SLH-DSA-SHA2-256s (FIPS 205, the plain method with an
227
+ empty context). A seal MUST carry exactly three signatures, in that
228
+ order, and counts as signed only if all three check. The third rests only
229
+ on fingerprint functions, so it would stand even if the mathematics
230
+ behind ML-DSA were broken. When this draft was written, no browser
231
+ offered it to a page, and Node.js offered it outside the standard
232
+ interface: a checker in a browser reports it as not checked, which is
233
+ never a pass.
234
+
235
+ The issuer's passkey signature on a slip is of today's kind only. No
236
+ device offers a quantum-safe passkey.
237
+
238
+ ## 4. The Slip
239
+
240
+ ### 4.1 Content
241
+
242
+ | Member | Meaning | Form |
243
+ |---|---|---|
244
+ | `type` | The kind of record | `provared.slip.v0` |
245
+ | `id` | Unique number | Section 3.7 |
246
+ | `issuer` | Who gives permission | An object, below |
247
+ | `agent` | Which agent may act | `{"name": text, "keys": key set}`, and optionally `"software"`, below |
248
+ | `actions` | What it may do | A list of 1 to 64 action names, none repeated |
249
+ | `limits` | How much | A list of 0 to 64 limits, below |
250
+ | `requires` | What must go with an action | A list of 0 to 64 conditions, below |
251
+ | `never` | Stated rules | A list of 0 to 16 names, below, none repeated |
252
+ | `with` | With whom it may deal | A list of 0 to 64 services, below |
253
+ | `passes` | How many times the permission may be passed on. Optional | A whole number from 1 to 10. Absent: it may not be passed on (section 25) |
254
+ | `validFrom` | From when | A time |
255
+ | `validUntil` | Until when | A time, later than `validFrom` |
256
+ | `purpose` | Why | Text, 1 to 1,000 characters |
257
+
258
+ `issuer` is `{"name": text, "key": passkey public key, "rpId": text,
259
+ "origin": text}`. `rpId` is the website the passkey belongs to (the
260
+ "relying party identifier" of the Web Authentication standard). `origin`
261
+ is the address of the page the slip was signed on, for example
262
+ `https://sign.example.org`. The host in `origin` MUST be `rpId` or end
263
+ with a full stop and `rpId`. `origin` MUST use `https`, or be
264
+ `http://localhost` with or without a port number. It holds nothing after
265
+ the host and the port.
266
+
267
+ A **name** is text of 1 to 200 characters. It is a label chosen by
268
+ whoever wrote the slip. It is not checked against anything, unless a
269
+ vouching record stands behind it (section 23).
270
+
271
+ `agent.software`, where present, is a list of 1 to 16 of `{"name": text,
272
+ "sha256": fingerprint}`: the agent's program and settings as the person
273
+ approved them. It is a statement. Nothing in a record proves which
274
+ program signed with the agent's keys, and a checker MUST show it as a
275
+ statement.
276
+
277
+ An **action name** is 1 to 64 characters: the lower-case letters a to z,
278
+ digits, full stops, hyphens and underscores, beginning with a letter or digit,
279
+ for example `supplies.order`. The issuer chooses the names. A checker
280
+ compares them exactly. Names that begin `provared.` are reserved for the
281
+ shared list of section 16: such a name MUST be on that list.
282
+
283
+ A **limit** names an `action`, which MUST be one of `actions`, and holds
284
+ exactly one of `max`, `each` and `count`, each a whole number:
285
+
286
+ | Limit | Meaning |
287
+ |---|---|
288
+ | `{"action", "max", "unit"}` | The amounts of all stubs under this slip for this action, added up, must not pass `max` |
289
+ | `{"action", "each", "unit"}` | No single stub for this action may have an amount above `each` |
290
+ | `{"action", "count"}` | There must not be more than `count` stubs for this action. `count` is 1 or more |
291
+ | `{"action", "max", "per", "unit"}` | As `max`, within any period of `per` seconds |
292
+ | `{"action", "count", "per"}` | As `count`, within any period of `per` seconds |
293
+
294
+ `unit` is 1 to 16 characters: the letters a to z and A to Z, digits,
295
+ full stops, hyphens and underscores, with no spaces, beginning with a
296
+ letter or a digit, for example `items` or `hours`. (A unit is shown
297
+ beside the checker's own words, so it is kept too short and too plain to
298
+ be mistaken for them.) A `count` has no
299
+ unit, and `each` has no period. `per` is from 1 to 31,622,400 (366 days).
300
+ A period is counted backwards from each stub, by the times the stubs
301
+ state. It holds every stub under the slip for the action, in whichever
302
+ chain (section 25) and at whichever place in the book, whose `when` is
303
+ later than this stub's `when` less `per` seconds and earlier than this
304
+ stub's `when`; every such stub with the same `when` that stands earlier
305
+ in the book; and this stub. There are no calendar days and no time
306
+ zones. A stub further on in the book, in another chain, may state an
307
+ earlier time, so a checker works these limits out once it has read every
308
+ stub under the slip. The finding is given for the stub whose period
309
+ holds too much, which may be a stub of another chain than the one that
310
+ was written last. A slip MUST NOT hold two limits with the same action, the same one
311
+ of `max`, `each` and `count`, and the same `per`.
312
+
313
+ A **condition** is `{"need": "countersignature"}` or `{"need":
314
+ "approval"}`, with these optional members: `action` (one of `actions`;
315
+ without it the condition applies to every action), and `above` with
316
+ `unit` (the condition applies only to a stub whose amount is more than
317
+ `above`; these two come together and need an `action`).
318
+ `countersignature` means the stub must carry the countersignature of the
319
+ service it names (section 6). `approval` means the stub must carry the
320
+ person's approval (section 17). A slip MUST NOT hold two conditions with
321
+ the same `need` and the same `action`.
322
+
323
+ Every `unit` named for one action, in its limits and its conditions, MUST
324
+ be the same, because a stub gives one amount.
325
+
326
+ A name in **`never`** is a kind of action or a rule of conduct from
327
+ section 16, for example `destroys` or `impersonate`. A slip MUST NOT
328
+ allow, in `actions`, a shared action of a kind that its `never` forbids.
329
+ A rule of conduct is the person's signed instruction to the agent. No
330
+ check of a record can show that the agent kept it (section 13).
331
+
332
+ A **service** is `{"id": text, "name": text}` or `{"id": text, "keys":
333
+ key set, "name": text}`. `id` has the form of an action name and MUST NOT
334
+ repeat within the slip. A service with no `keys` cannot countersign.
335
+
336
+ ### 4.2 How a passkey signs a slip
337
+
338
+ A passkey does not sign a document. It signs a short value the web page
339
+ hands to it (the challenge), together with the address of the website.
340
+
341
+ 1. Write the content in the canonical form. Build the signing input
342
+ (section 3.1) with the slip's protected header (section 3.2).
343
+ 2. The challenge is the SHA-256 hash of the signing input.
344
+ 3. Ask the passkey to sign with that challenge, with the person confirmed
345
+ by the device ("user verification: required").
346
+ 4. The passkey returns three values: the authenticator data, the client
347
+ data, and the signature. Store all three exactly as returned.
348
+
349
+ ### 4.3 The signed slip
350
+
351
+ A slip has exactly one signature entry:
352
+
353
+ ```json
354
+ {
355
+ "protected": "<the slip's protected header>",
356
+ "header": { "authenticatorData": "<base64url>", "clientDataJSON": "<base64url>" },
357
+ "signature": "<base64url of the signature as the passkey returned it>"
358
+ }
359
+ ```
360
+
361
+ `header` MUST hold exactly those two members.
362
+
363
+ ### 4.4 Checking a slip
364
+
365
+ A checker follows the checking steps of the Web Authentication standard
366
+ (W3C Web Authentication Level 3, section 7.2), as far as they apply to a
367
+ check made later and offline. It MUST confirm all of these:
368
+
369
+ 1. The envelope, the label, the canonical form and every member are as
370
+ sections 3 and 4.1 require.
371
+ 2. The client data is JSON whose `type` is `webauthn.get`.
372
+ 3. The client data's `challenge` is the base64url of the SHA-256 hash of
373
+ the signing input.
374
+ 4. The client data's `origin` equals `issuer.origin`, and `crossOrigin`
375
+ is not true.
376
+ 5. The authenticator data is at least 37 bytes. Its first 32 bytes equal
377
+ the SHA-256 hash of `issuer.rpId`.
378
+ 6. In the flags byte, "user present" (bit 0) and "user verified" (bit 2)
379
+ are both set. "Attested credential data" (bit 6) is not set. If
380
+ "extension data" (bit 7) is not set, the authenticator data is exactly
381
+ 37 bytes.
382
+ 7. The signature fits `issuer.key`, over the authenticator data followed
383
+ by the SHA-256 hash of the client data. For an `ES256` key the stored
384
+ signature is in ASN.1 DER form and MUST be strictly encoded.
385
+
386
+ If the checker was given the thumbprints of the issuer keys it expects,
387
+ it MUST also confirm that `issuer.key` is one of them. If it was given
388
+ none, it MUST say that the issuer's key was not compared with a known
389
+ key.
390
+
391
+ The signature counter in the authenticator data is not used: an offline
392
+ checker keeps no state.
393
+
394
+ ## 5. The Stub
395
+
396
+ ### 5.1 Content
397
+
398
+ | Member | Meaning | Form |
399
+ |---|---|---|
400
+ | `type` | The kind of record | `provared.stub.v0` |
401
+ | `id` | Unique number | Section 3.7 |
402
+ | `slip` | The slip relied on | The slip's fingerprint |
403
+ | `seq` | Place in the chain | A whole number: 0 for the first stub under the slip, then 1, 2, … |
404
+ | `previous` | The stub before | The fingerprint of the stub with the number before. Present unless `seq` is 0 |
405
+ | `action` | What was done | An action name |
406
+ | `amount` | How much. Optional | `{"unit": text, "value": whole number}` |
407
+ | `with` | With whom. Optional | The `id` of a service in the slip |
408
+ | `details` | The documents involved. Optional | A list of 1 to 32 of `{"name": text, "sha256": fingerprint of the document}` |
409
+ | `approval` | The person's approval of this action. Optional | The fingerprint of the approval (section 17) |
410
+ | `terms` | The service's terms the agent relied on. Optional; needs `with` | The fingerprint of the terms (section 19) |
411
+ | `pass` | For a helper agent: the pass it acts under. Optional | The fingerprint of the pass (section 25) |
412
+ | `when` | When it was done | A time |
413
+
414
+ A stub holds fingerprints of documents, never the documents.
415
+
416
+ ### 5.2 Signing and checking
417
+
418
+ A stub is signed by the agent's key set (section 3.9), with the stub
419
+ labels of section 3.2.
420
+
421
+ A checker MUST confirm that both signatures check against the two keys
422
+ the slip gives for the agent.
423
+
424
+ ## 6. The countersignature
425
+
426
+ Content: `{"stub": fingerprint of the stub, "type":
427
+ "provared.countersignature.v0", "when": a time}`. It means: "this action
428
+ happened with me".
429
+
430
+ It is signed by the service's key set, with the countersignature labels
431
+ of section 3.2. A checker MUST confirm that `stub` is the fingerprint of
432
+ the stub it accompanies, and that both signatures check against the keys
433
+ the slip gives for the service named in the stub's `with`.
434
+
435
+ A stub with no countersignature is **one-sided**. It is a named state,
436
+ not a failure. It proves what the agent's side said. A checker MUST show
437
+ it as one-sided.
438
+
439
+ ## 7. The chain
440
+
441
+ There is one chain for the stubs of the slip's own agent, and one for the
442
+ stubs under each pass (section 25). For the stubs of one chain, taken in
443
+ the order they appear in a book, a checker MUST confirm:
444
+
445
+ - the first has `seq` 0 and no `previous`;
446
+ - each later one has the next number, and `previous` equal to the
447
+ fingerprint of the one before;
448
+ - `when` never goes backwards;
449
+ - no `id` appears twice in the book, among records of every kind
450
+ (`duplicate-id`).
451
+
452
+ ## 8. What a stub shows about the agent
453
+
454
+ These are not faults in the record. A sound record can show that the
455
+ agent went outside its slip. A checker reports each of them, and at which
456
+ stub:
457
+
458
+ | Code | Shown when |
459
+ |---|---|
460
+ | `action-not-allowed` | `action` is not in the slip's `actions` |
461
+ | `party-not-allowed` | `with` is not the `id` of a service in the slip |
462
+ | `outside-valid-time` | `when` is before `validFrom`, or not before `validUntil` |
463
+ | `amount-missing` | The slip has a limit or a condition with a `unit` for this action, and the stub has no amount in that unit. Reported once for a stub |
464
+ | `over-limit` | The running total for this action, with this stub added, is more than a limit's `max` |
465
+ | `over-each-limit` | The stub's amount is more than a limit's `each` |
466
+ | `over-count-limit` | With this stub there are more stubs for this action than a limit's `count` |
467
+ | `over-period-limit` | Within the period that ends at this stub, the total is more than `max`, or the number of stubs is more than `count` |
468
+ | `countersignature-missing` | A condition asks for a countersignature, and the stub has none |
469
+ | `approval-missing` | A condition asks for the person's approval, and the stub has none |
470
+ | `prohibited` | `action` is a shared action of a kind the slip's `never` forbids |
471
+ | `after-cancellation` | The person cancelled the slip before this stub (section 22) |
472
+ | `pass-not-allowed` | The stub was written under a pass that the slip does not allow (section 25) |
473
+ | `outside-terms` | The stub relies on a service's terms (section 19), and the terms do not accept `action`, or `when` is before their `validFrom` or not before their `validUntil` |
474
+
475
+ A stub is compared with its slip only if the stub passed its own check.
476
+ Totals, counts and periods take in only the stubs that were compared. A
477
+ pass that hands on more than its writer holds is reported on the pass
478
+ (`pass-wider`, section 25).
479
+
480
+ The order in which a checker reports several findings for one entry is
481
+ not part of this format: two checkers agree if they report the same set.
482
+ Where an entry fails its own check in several ways, a checker MUST report
483
+ at least one of them, and MAY stop at the first.
484
+
485
+ A checker answers three questions and keeps them apart: was a problem
486
+ found in the record; was every signature checked on this device; and what
487
+ do the stubs show about the agent. It MUST call a record intact only if no
488
+ problem was found and every signature was checked. It MUST say that the
489
+ agent stayed within its slip only if every stub was compared with its slip
490
+ and none was outside it. If the checker itself meets something it did not
491
+ expect, it MUST report a problem, never a pass.
492
+
493
+ ## 9. The book
494
+
495
+ A book is UTF-8 text. Each line is one entry, ended by a line feed (the
496
+ line feed after the last line may be missing). An
497
+ entry is a JSON object in the canonical form (section 3.4, with records
498
+ in place of the narrowed content), and is one of:
499
+
500
+ - `{"slip": slip record}`
501
+ - `{"stub": stub record}`, which MAY also hold `"countersignature":
502
+ countersignature record` and `"approval": approval record`
503
+ - `{"refusal": refusal record}`
504
+ - `{"terms": terms record}`
505
+ - `{"seal": seal record}`, which MAY also hold `"stamps": list of 1 to 4
506
+ time-stamps` (section 21)
507
+ - `{"cancellation": cancellation record}`, which MAY also hold `"stamps"`
508
+ (section 22)
509
+ - `{"acknowledgement": acknowledgement record}` (section 26)
510
+ - `{"vouching": vouching record}` and `{"withdrawal": withdrawal record}`
511
+ (section 23)
512
+ - `{"pass": pass record}` (section 25)
513
+
514
+ A slip MUST come before the entries that rely on it, and a set of terms
515
+ before the stubs that rely on it. A book MUST NOT hold
516
+ the same slip twice, nor more than 100,000 entries. A line MUST NOT be
517
+ longer than 131,072 bytes.
518
+
519
+ ## 10. The tree and the top fingerprint
520
+
521
+ The entries of a book are the leaves of a Merkle tree built exactly as
522
+ RFC 6962 (Certificate Transparency), section 2.1, sets out, with SHA-256.
523
+ The data of a leaf is the bytes of its line, without the line feed. The
524
+ root of the tree is the book's **top fingerprint**.
525
+
526
+ A top fingerprint is signed, with the number of entries, by a seal
527
+ (section 21), and an outside time-stamp on the seal states when. Without
528
+ a seal that the checker has reason to trust, a top fingerprint is worth
529
+ as much as the checker's other reason to trust it, for example a copy
530
+ they took earlier.
531
+
532
+ The top fingerprint does not by itself fix how many entries the book
533
+ holds: that is a property of this kind of tree. Whoever keeps a copy of a
534
+ top fingerprint MUST keep the number of entries with it, and a later
535
+ signature or time-stamp MUST cover both, as RFC 6962 section 3.5 does. A
536
+ checker that is given a top fingerprint or a number of entries to expect
537
+ MUST compare it.
538
+
539
+ ## 11. The Show: one page, with proof
540
+
541
+ A Show hands a checker some entries of a book and, for each, the few
542
+ fingerprints needed to work out the top fingerprint again (the audit path
543
+ of RFC 6962, section 2.1.1).
544
+
545
+ ```json
546
+ {
547
+ "type": "provared.show.v0",
548
+ "size": 12,
549
+ "root": "<the top fingerprint>",
550
+ "pages": [
551
+ { "index": 3, "entry": "<the line, exactly>", "path": ["<fingerprint>", "…"] }
552
+ ]
553
+ }
554
+ ```
555
+
556
+ A Show MAY also hold `"seal"`: an entry of the form `{"seal": seal
557
+ record}`, with or without `"stamps"`. The Show is then of the book as it
558
+ stood when that seal was made: the seal's `size` and `root` MUST equal the
559
+ Show's (`seal-mismatch`), and a checker checks the seal and its
560
+ time-stamps as section 21 sets out. Its `id` MUST NOT be that of a
561
+ record on any page (`duplicate-id`), as in a whole book (section 7).
562
+ Such a Show proves that its pages existed by the time the time-stamp
563
+ states, with no other copy of the top fingerprint.
564
+
565
+ A Show holds 1 to 64 pages, none repeated. It is not itself signed. A checker
566
+ MUST confirm each page with the checking steps of RFC 9162, section
567
+ 2.1.3.2, then check each entry as above. A stub can be checked only if
568
+ its slip is among the pages, and a stub that relies on a service's terms
569
+ only if those terms are among the pages. A Show can show a stub outside
570
+ its slip, including a single stub that passes a limit by itself, and a
571
+ stub that lacks a countersignature or an approval the slip asks for. It
572
+ cannot show a count, that a limit was kept, or that an approval was used
573
+ only once: those need every stub under the slip. Nor can it show that a
574
+ slip was not cancelled (section 22), or that a vouching record was not
575
+ withdrawn (section 23), on a page that is not among its pages. A checker
576
+ MUST say both with every Show.
577
+
578
+ Whoever hands over a Show chooses its pages and its seal. So a Show does
579
+ not show what a seal that was left out of it would show. Where a page is
580
+ dated after the time-stamp of a seal that comes after it in the book,
581
+ that is reported only if the seal is among the pages, and the seal is
582
+ the page reported (section 21.3). Only the whole book shows it in every
583
+ case.
584
+
585
+ The same holds for the rules that rest on a seal earlier in the book
586
+ (section 21.1, rule 4, and section 21.3, the second case): a Show
587
+ applies them only for seals that are among its pages. With such a seal
588
+ left out, a Show may pass where the whole book reports a seal as dated
589
+ before a time-stamp it covers; it may count a block time-stamp that the
590
+ whole book sets aside, and so show its pages as having existed earlier
591
+ than the whole book shows; and it may report a seal as dated after its
592
+ block time-stamp where the whole book sets that time-stamp aside and
593
+ passes. The last two need a block that states a time far behind the
594
+ true time.
595
+
596
+ Nothing fixes the time-stamps beside the seal that comes with a Show.
597
+ They stand outside the tree and outside the seal's signatures, so
598
+ whoever hands the Show over can put a later time-stamp in the place of
599
+ an earlier one. The same holds for the last seal of a book. A later
600
+ time-stamp shows less, never more, and the pages are still held against
601
+ the seal's own date (section 21.1, rule 4).
602
+
603
+ ## 12. Not in draft version 0
604
+
605
+ | Missing | What follows |
606
+ |---|---|
607
+ | A public place where seals are kept | The last seal of a book, with everything after it, can be removed unnoticed, unless someone else holds a copy of that seal or of its top fingerprint and number of entries |
608
+ | A quantum-safe time-stamp | Time-stamp services sign with methods of today's kind |
609
+ | Covered fields outside a slip's names and purpose | Every other field of an entry is visible to whoever holds it |
610
+ | A compact binary form | Records are JSON text only |
611
+
612
+ ## 13. What a record does not prove
613
+
614
+ - It proves what was recorded, not what was left out. An agent that acts
615
+ and writes no stub leaves no trace.
616
+ - A one-sided stub proves what the agent's side said, not what the other
617
+ side did.
618
+ - A refusal proves what the service's side said, not what the agent did.
619
+ - A rule of conduct in a slip, such as "never claim to be a human being",
620
+ is the person's signed instruction. No check can show that the agent
621
+ kept it.
622
+ - An approval proves that the passkey approved that one action. It does
623
+ not prove that the person read what they approved.
624
+ - It does not show that an action was wise, lawful or wanted.
625
+ - A badly written slip is faithfully recorded as a badly written slip.
626
+ - It does not prove who was holding the device when the passkey signed.
627
+ - A name in a record is a label. Only keys are checked. A vouching
628
+ record shows which organisation stood behind a name; it does not prove
629
+ that the organisation checked well.
630
+ - The fingerprints of an agent's software in a slip are a statement of
631
+ what the person approved, not proof of what ran.
632
+
633
+ ## 14. Standards used
634
+
635
+ | Standard | Used for |
636
+ |---|---|
637
+ | RFC 8259 (JSON); RFC 8785 (JSON Canonicalization Scheme) | Writing the content |
638
+ | RFC 7515 (JSON Web Signature), sections 5.1 and 7.2.1 | The signed envelope |
639
+ | RFC 7517 (JSON Web Key); RFC 7638 (thumbprints) | Keys and their names |
640
+ | RFC 8725, section 3.11 | Labels (explicit typing) |
641
+ | RFC 8032; RFC 8037; RFC 9864 | Ed25519 and its names |
642
+ | FIPS 204; RFC 9964 | ML-DSA-87 and its names |
643
+ | FIPS 180-4 | SHA-256 |
644
+ | W3C Web Authentication Level 3, section 7.2 | Passkey signatures |
645
+ | FIPS 186-5; RFC 7518; RFC 8017 | The signing methods passkeys use (ES256, RS256) |
646
+ | RFC 4648, section 5 | Base64url |
647
+ | RFC 3339 | Times |
648
+ | RFC 6962, section 2.1; RFC 9162, section 2.1.3.2 | The tree and its proofs |
649
+ | FIPS 205 | SLH-DSA-SHA2-256s, the third signature on a seal |
650
+ | RFC 3161; RFC 5652; RFC 5280; ITU-T X.690 | Time-stamps: the statement, its signed wrapper, the certificate, and the byte layout (DER) |
651
+ | The OpenTimestamps proof file, version 1 (an open format; not the work of a standards body) | Block time-stamps: the steps from a fingerprint to the Merkle root of a block |
652
+ | RFC 9901 (Selective Disclosure for JSON Web Tokens) | Covered fields |
653
+
654
+ ## 15. Choices that go beyond the standards
655
+
656
+ Each of these is a choice of this draft, to be reviewed before the format
657
+ is frozen.
658
+
659
+ 1. The method name `prova.red/webauthn/v0`: a passkey signature wrapped
660
+ as a JSON Web Signature. No registered name exists for it.
661
+ 2. The media types of section 3.2 (`vnd.provared.slip.v0+json` and
662
+ the others, each ending in `.v0+json`) are not registered.
663
+ 3. Protected headers are fixed texts, compared byte for byte.
664
+ 4. The hybrid is two signatures side by side with the rule "both must
665
+ check", not a combined signature.
666
+ 5. The content is narrowed to whole numbers, strings, lists and objects.
667
+ 6. A fingerprint covers the content only, not the signatures.
668
+ 7. The kinds of limit, the conditions and the `never` list of section 4.1.
669
+ 8. A period is counted backwards from each stub, in seconds, with no
670
+ calendar days and no time zones.
671
+ 9. The shared list of actions, the kinds of action and the rules of
672
+ conduct of section 16. They are a first draft, written before real
673
+ agents have used them.
674
+ 10. The approval, the refusal and the terms for agents of sections 17 to
675
+ 19, and the labels `vnd.provared.approval.v0+json`,
676
+ `vnd.provared.refusal.v0+json` and `vnd.provared.terms.v0+json`.
677
+
678
+ 11. The seal of section 21, its label `vnd.provared.seal.v0+json`, and
679
+ its three signatures side by side. The name `SLH-DSA-SHA2-256s` is
680
+ used as FIPS 205 gives it.
681
+ 12. A checker trusts a time-stamp service by the fingerprint of the
682
+ service's certificate, given by the person checking. It follows no
683
+ chain of certificates.
684
+ 13. A time-stamp is made over the seal's fingerprint. The allowance
685
+ between clocks is 300 seconds. A time-stamp that states its own time
686
+ more loosely than that is refused.
687
+ 13a. The block time-stamp of section 21.4: the proof read strictly, with
688
+ three kinds of step only; the block's header kept beside the proof; a
689
+ block trusted by its fingerprint, given by the person checking, or
690
+ found in a chain of block headers the checker checks itself, with
691
+ known blocks and six blocks after it; a block's time taken as right
692
+ to within 7,200 seconds.
693
+
694
+ 14. The cancellation, the vouching record and the withdrawal of sections
695
+ 22 and 23, and their labels.
696
+ 15. A stub counts as made before a time-stamped cancellation only if an
697
+ outside time-stamp shows that it existed by then.
698
+
699
+ 16. Covered fields follow RFC 9901, narrowed as section 24 sets out: only
700
+ a slip's names and purpose; never an item of a list; exactly one
701
+ fingerprint where a field is covered, with no decoys; disclosures in
702
+ the canonical form; SHA-256 only; disclosures kept beside the record,
703
+ not inside a line of the book.
704
+
705
+ 17. The pass of section 25, its label, and one chain of stubs for each
706
+ pass.
707
+ 18. The acknowledgement of section 26 and its label
708
+ `vnd.provared.acknowledgement.v0+json`.
709
+
710
+ ## 16. The shared list: actions, kinds of action, rules of conduct
711
+
712
+ Anyone may use action names of their own. So that one organisation's slip
713
+ can be read by another, this format also keeps a shared list. Every name
714
+ on it begins `provared.`, and belongs to exactly one kind of action.
715
+
716
+ The kinds of action:
717
+
718
+ | Kind | Meaning |
719
+ |---|---|
720
+ | `reads` | Looks at data without changing it. |
721
+ | `changes` | Creates or changes data in a way that can be put back. |
722
+ | `destroys` | Removes data or a resource in a way that may not be put back. |
723
+ | `sends` | Sends a message or data to a person, to the public or to another system. |
724
+ | `commits` | Binds the person to something: an order, a booking, an agreement, an account. |
725
+ | `grants` | Gives someone or something access or permission. |
726
+ | `runs` | Runs a program or a command. |
727
+ | `enters` | Signs in to a system or an account. |
728
+
729
+ The shared actions:
730
+
731
+ | Action | Kind | Meaning |
732
+ |---|---|---|
733
+ | `provared.data.read` | `reads` | Read stored data or a file. |
734
+ | `provared.data.search` | `reads` | Search stored data. |
735
+ | `provared.data.create` | `changes` | Create a new item of data or a new file. |
736
+ | `provared.data.change` | `changes` | Change an item of data or a file that exists. |
737
+ | `provared.data.delete` | `destroys` | Delete data or a file. |
738
+ | `provared.data.export` | `sends` | Copy data out of the system that keeps it. |
739
+ | `provared.message.read` | `reads` | Read messages. |
740
+ | `provared.message.draft` | `changes` | Write a message without sending it. |
741
+ | `provared.message.send` | `sends` | Send a message to a person. |
742
+ | `provared.post.publish` | `sends` | Publish something where the public can see it. |
743
+ | `provared.calendar.read` | `reads` | Read a calendar. |
744
+ | `provared.calendar.change` | `changes` | Add, move or remove an entry in a calendar. |
745
+ | `provared.booking.make` | `commits` | Book a place, a time or a service. |
746
+ | `provared.booking.cancel` | `commits` | Cancel a booking. |
747
+ | `provared.order.place` | `commits` | Place an order for goods or services. |
748
+ | `provared.order.cancel` | `commits` | Cancel an order. |
749
+ | `provared.terms.accept` | `commits` | Accept terms, or sign an agreement. |
750
+ | `provared.form.submit` | `commits` | Submit a form or an application. |
751
+ | `provared.account.create` | `commits` | Open an account. |
752
+ | `provared.account.sign-in` | `enters` | Sign in to an account or a system. |
753
+ | `provared.access.grant` | `grants` | Give a person or a program access. |
754
+ | `provared.access.remove` | `changes` | Take access away from a person or a program. |
755
+ | `provared.key.create` | `grants` | Make a key or a password that gives access. |
756
+ | `provared.code.read` | `reads` | Read the source of a program. |
757
+ | `provared.code.change` | `changes` | Change the source of a program. |
758
+ | `provared.code.run` | `runs` | Run a program or a command. |
759
+ | `provared.code.release` | `runs` | Put a program into live use. |
760
+ | `provared.system.configure` | `changes` | Change the settings of a system. |
761
+ | `provared.web.read` | `reads` | Read a public web page. |
762
+ | `provared.agent.instruct` | `sends` | Hand a task to another agent. |
763
+
764
+ The rules of conduct that a slip's `never`, or a service's terms, may
765
+ state:
766
+
767
+ | Rule | Meaning |
768
+ |---|---|
769
+ | `impersonate` | Never claim to be a human being, or to be anyone other than the agent of the person who signed the slip. |
770
+ | `bypass` | Never go around an access control, a block or a refusal. |
771
+ | `escalate` | Never obtain or use access that it was not given. |
772
+ | `conceal` | Never hide, alter or leave out its own records. |
773
+ | `deceive` | Never state what it has reason to believe is false, and never make up a record or a result. |
774
+ | `harass` | Never threaten, pressure or attack a person. |
775
+ | `disclose` | Never pass information that is not public to anyone the slip does not name. |
776
+ | `continue-after-stop` | Never carry on after being told to stop. |
777
+
778
+ A `never` list MAY hold the name of any kind of action and of any rule of
779
+ conduct above.
780
+
781
+ ## 17. The approval
782
+
783
+ A slip may ask for the person's own approval of an action (section 4.1).
784
+ The person gives it with the same passkey that signed the slip.
785
+
786
+ Content:
787
+
788
+ | Member | Meaning | Form |
789
+ |---|---|---|
790
+ | `type` | The kind of record | `provared.approval.v0` |
791
+ | `id` | Unique number | Section 3.7 |
792
+ | `slip` | The slip | The slip's fingerprint |
793
+ | `action` | What is approved | An action name |
794
+ | `amount`, `with`, `details` | Optional | As in a stub (section 5.1) |
795
+ | `when` | When it was given | A time |
796
+
797
+ It is signed as a slip is (sections 4.2 and 4.3), with the approval label
798
+ of section 3.2. An approval is for exactly one action. The stub names it
799
+ by its fingerprint, in `approval`, and the approval is kept on the same
800
+ line of the book as the stub.
801
+
802
+ A checker MUST confirm all of these, and otherwise report a problem:
803
+
804
+ 1. The approval's fingerprint is the one the stub names
805
+ (`approval-mismatch`; a stub that names an approval which is not with
806
+ it: `approval-not-found`).
807
+ 2. Its `slip` is the stub's `slip`, and its `action`, `amount`, `with` and
808
+ `details` are each the same as the stub's, or absent from both
809
+ (`approval-mismatch`).
810
+ 3. Its `id` is not the `id` of an approval on an earlier line
811
+ (`approval-reused`), nor of any other record (`duplicate-id`). Single
812
+ pages cannot show this.
813
+ 4. The passkey signature checks, by the steps of section 4.4, against the
814
+ `issuer` of the slip (`approval-invalid`).
815
+ 5. Its `when` is not more than 300 seconds after the stub's `when`
816
+ (`approval-dated-after-stub`). The stub names the approval, so the
817
+ stub was signed after the approval was written.
818
+
819
+ ## 18. The refusal
820
+
821
+ A service that refuses what an agent asked for may say so in a record of
822
+ its own. It leaves evidence of the attempt even if the agent's own record
823
+ is silent.
824
+
825
+ Content:
826
+
827
+ | Member | Meaning | Form |
828
+ |---|---|---|
829
+ | `type` | The kind of record | `provared.refusal.v0` |
830
+ | `id` | Unique number | Section 3.7 |
831
+ | `slip` | The slip the agent showed | The slip's fingerprint |
832
+ | `by` | Who refused | `{"keys": key set, "name": text}` |
833
+ | `action` | What the agent asked for | An action name. A name that begins `provared.` need not be on the shared list here: what was asked for is written down as it was asked |
834
+ | `amount` | Optional | `{"unit": text, "value": whole number}` |
835
+ | `reason` | Why | One of the names below |
836
+ | `when` | When | A time |
837
+
838
+ | Reason | Meaning |
839
+ |---|---|
840
+ | `not-in-slip` | The slip does not cover the action, or does not name this service. |
841
+ | `over-limit` | The action would pass a limit of the slip. |
842
+ | `outside-valid-time` | The slip was not in force at that time. |
843
+ | `slip-not-sound` | The slip did not pass its check. |
844
+ | `needs-approval` | The slip asks for the person's approval, and none was shown. |
845
+ | `against-terms` | The service's terms for agents do not accept the action. |
846
+ | `other` | Another reason. |
847
+
848
+ It is signed with the key set in `by`, with the refusal labels of section
849
+ 3.2. A checker MUST confirm both signatures against `by.keys`, and MUST
850
+ say whether those keys are the keys the slip gives for one of its
851
+ services, or the keys of a party the slip does not name.
852
+
853
+ A refusal is one-sided: it is the service's statement. A checker MUST show
854
+ it as such, and MUST NOT count it as the agent going outside its slip.
855
+
856
+ ## 19. A service's terms for agents
857
+
858
+ A service may state which actions it accepts from agents.
859
+
860
+ Content:
861
+
862
+ | Member | Meaning | Form |
863
+ |---|---|---|
864
+ | `type` | The kind of record | `provared.terms.v0` |
865
+ | `id` | Unique number | Section 3.7 |
866
+ | `by` | Whose terms | `{"keys": key set, "name": text}` |
867
+ | `accepts` | The actions it accepts | A list of 1 to 64 action names, none repeated |
868
+ | `never` | What it asks of agents | A list of 0 to 16 names from section 16, none repeated |
869
+ | `validFrom`, `validUntil` | When the terms are in force | Times; the second later than the first |
870
+
871
+ Terms MUST NOT accept a shared action of a kind that their own `never`
872
+ forbids. A rule of conduct in `never` is what the service asks of agents;
873
+ no check can show that an agent kept it.
874
+
875
+ It is signed with the key set in `by`, with the terms labels of section
876
+ 3.2. A stub that relied on the terms names their fingerprint in `terms`.
877
+ A checker MUST show the fingerprint of the key set that signed a set of
878
+ terms or a refusal: the name in `by` is a label.
879
+
880
+ For such a stub a checker MUST confirm that the terms are earlier in the
881
+ book (`terms-not-found`), that they passed their own check
882
+ (`terms-unusable`), and that `by.keys` are exactly the keys the slip gives
883
+ for the service the stub names (`terms-mismatch`). It then reports
884
+ `outside-terms` as section 8 sets out.
885
+
886
+ How a service publishes its terms, for example at an address on its
887
+ website, is not part of this draft.
888
+
889
+ ## 20. The check before acting
890
+
891
+ The software around an agent may ask, before each action, whether the
892
+ action would be outside the slip, and stop the action if so. The answer
893
+ MUST come from the same comparison as section 8, made over the book so
894
+ far. An action MUST be refused beforehand if, with its stub written, a
895
+ checker would report a finding for that stub, or because of it for a
896
+ stub dated after it. One case goes further. An action that would fall in
897
+ a period (a limit "within a period", section 4.1) which ends at a stub
898
+ dated after it, and which already holds more than the limit allows, MUST
899
+ be refused as well (`over-period-limit`): it would add to a period that
900
+ holds too much. A checker reports nothing new for it, because the
901
+ finding stands with the later stub. The answer MUST be that nothing is allowed
902
+ (`record-not-sound`) if the book so far has a problem, if any signature
903
+ in it could not be checked on that device, or if the check was not told
904
+ which issuer keys it trusts. An action dated before the last stub of
905
+ its own chain (the agent's, or the helper's under its pass; section 7)
906
+ is refused (`time-went-backwards`).
907
+
908
+ Where the slip asks for the person's approval, the action is allowed
909
+ only if the signed approval is handed to the check and passes the checks
910
+ of section 17. Where the slip asks for a countersignature, the check
911
+ says so: the action is inside the slip only if the other side then
912
+ countersigns it. Where the action names no service, or a service for
913
+ which the slip gives no keys, no countersignature could be given, and
914
+ the action is not allowed (`countersignature-missing`). An action whose
915
+ record, with its approval and a countersignature, could be longer than a
916
+ line of a book may be (section 9) is not allowed either (`too-large`).
917
+
918
+ This is a help to whoever runs the agent. It is not evidence: nothing in a
919
+ record shows that the check was made.
920
+
921
+ ## 21. The Seal and the outside time-stamp
922
+
923
+ Whoever keeps a book (the recorder) seals it from time to time. A seal
924
+ fixes everything before it. An outside time-stamp on the seal states
925
+ when, in words the recorder cannot change afterwards.
926
+
927
+ ### 21.1 The seal
928
+
929
+ Content:
930
+
931
+ | Member | Meaning | Form |
932
+ |---|---|---|
933
+ | `type` | The kind of record | `provared.seal.v0` |
934
+ | `id` | Unique number | Section 3.7 |
935
+ | `by` | The recorder | `{"keys": the recorder's three keys, "name": text}` |
936
+ | `size` | How many entries the book held | A whole number, 1 or more |
937
+ | `root` | The top fingerprint of those entries | A fingerprint (section 10) |
938
+ | `previous` | The seal before this one in the book. Absent for the first | That seal's fingerprint |
939
+ | `when` | When it was made, as the recorder states | A time |
940
+
941
+ It is signed with the three keys in `by`, with the seal labels of section
942
+ 3.2. A seal is added to the book as its next entry, so the seal at entry
943
+ number n covers the n entries before it, and the next seal covers this
944
+ one too.
945
+
946
+ A checker that holds the whole book MUST confirm all of these, and
947
+ otherwise report a problem:
948
+
949
+ 1. All three signatures check against `by.keys` (`signature-invalid`).
950
+ 2. `size` is the number of entries before the seal, and `root` is their
951
+ top fingerprint (`seal-mismatch`).
952
+ 3. `previous` is the fingerprint of the seal before it in the book, and
953
+ is absent if there is none (`seal-chain-broken`).
954
+ 4. `when` is not earlier than the `when` of the seal before it
955
+ (`time-went-backwards`). `when` is also not more than 300 seconds
956
+ earlier than the latest time stated by an entry it covers that passed
957
+ its own check (`time-went-backwards`): one of the two dates is then
958
+ not as it says. There is one exception. Where the seal has a counted
959
+ time-stamp and that entry states a time more than 300 seconds after
960
+ the time the time-stamp counts as stating, the time-stamp settles
961
+ which date is wrong for that entry: the entry is reported instead
962
+ (section 21.3), and it does not count against the seal. Every other
963
+ entry the seal covers is still compared with the seal's `when`. The
964
+ same rule holds for a seal that comes with a Show, against the Show's
965
+ pages (section 11). The times
966
+ an entry states are its own `when` and the `when` of a
967
+ countersignature or an approval on the same line.
968
+ `when` is also not more than 300 seconds earlier than the latest time
969
+ that a counted time-stamp from a service gave any seal before it
970
+ (`time-went-backwards`). A seal covers the lines of the seals before
971
+ it, time-stamps included, so it cannot have been made before a
972
+ time-stamp that one of those lines holds. Among the pages of a Show,
973
+ and for the seal that comes with a Show, the seals before it are
974
+ those among the pages.
975
+ 5. If the checker was given the fingerprints of the key sets of the
976
+ recorders it expects, the fingerprint of `by.keys` is one of them
977
+ (`sealer-not-expected`). If it was given none, it MUST say that the
978
+ seal's keys were not compared with keys it trusts.
979
+
980
+ The **fingerprint of a key set** is the SHA-256 hash of the list of keys
981
+ written in the canonical form (section 3.4), in base64url.
982
+
983
+ ### 21.2 The time-stamps
984
+
985
+ An entry that holds a seal MAY hold, in `stamps`, 1 to 4 time-stamps,
986
+ none repeated. There are two kinds. A time-stamp from a service, set out
987
+ here, is text. A block time-stamp, set out in section 21.4, is an object.
988
+
989
+ A time-stamp from a service
990
+ is a "TimeStampToken" as RFC 3161, section 2.4.2, sets out, in DER,
991
+ written in base64url, of at most 12,288 bytes. What it stamps (its
992
+ "message imprint") MUST be the seal's fingerprint: the fingerprint method
993
+ SHA-256, and the 32 bytes of the fingerprint. It MUST carry the
994
+ certificate of the service that signed it.
995
+
996
+ A checker reads the time-stamps of a seal only if none of the seal's own
997
+ signatures failed. For each time-stamp it MUST confirm all of these, and
998
+ otherwise report a problem:
999
+
1000
+ 1. It is laid out as RFC 3161 and RFC 5652 set out, in strict DER
1001
+ (`stamp-bad-data`). Every part is read, including parts the checker
1002
+ does not otherwise use: a whole number or an object identifier that is
1003
+ not in its shortest form, a part that does not fill what holds it, or a
1004
+ part the standards do not allow in that place, is refused. The signed
1005
+ data is of version 3, with exactly one signer.
1006
+ 2. What it stamps is this seal's fingerprint (`stamp-wrong-data`).
1007
+ 3. Its signed attributes name a time-stamp statement, hold the
1008
+ fingerprint of the statement, and name the certificate that signed, by
1009
+ the "signing certificate" attribute that RFC 3161, section 2.4.2,
1010
+ requires (in the form of RFC 5035, or the older form of RFC 2634). The
1011
+ time-stamp carries that certificate, and the signature over the
1012
+ attributes fits its public key (`stamp-invalid`). A certificate with
1013
+ the same key and other contents is another certificate.
1014
+ 4. The fingerprint method used to check the signature is the one the
1015
+ signer names (RFC 5652, section 5.4): SHA-256, SHA-384 or SHA-512. A
1016
+ signing method that names another one is refused (`stamp-invalid`).
1017
+ The signing methods are RSA (PKCS #1 version 1.5; keys of 2,048 to
1018
+ 8,192 bits, with a public number of at most 32 bits), ECDSA on the
1019
+ curves P-256 and P-384, and Ed25519.
1020
+ 5. The time it states lies within the time that certificate is in force
1021
+ (`stamp-invalid`).
1022
+ 6. It does not say that its time is exact to no better than more than 300
1023
+ seconds, and it carries no extension marked as one that must be
1024
+ understood (`stamp-invalid`).
1025
+ 7. If it is counted (below): the seal's `when` is not more than 300
1026
+ seconds after the time it states (`dated-after-stamp`). A block
1027
+ time-stamp that section 21.3 sets aside is the one exception.
1028
+
1029
+ The time a time-stamp states is taken to the second, rounded down.
1030
+
1031
+ **Whom to trust is the checker's choice.** The person checking gives the
1032
+ fingerprint (SHA-256, in base64url) of the certificate of each time-stamp
1033
+ service they trust. A time-stamp counts only if the certificate it names
1034
+ is one of those, and only if all three signatures of the seal were
1035
+ checked on that device. A sound time-stamp from any other service MUST
1036
+ be shown as not counted, with the fingerprint of its certificate, and
1037
+ MUST NOT be treated as a time: it is compared with nothing. This format
1038
+ names no service.
1039
+
1040
+ A checker follows no chain of certificates and asks no outside party. It
1041
+ does not read what a certificate says its key may be used for: the person
1042
+ checking decides that by naming the certificate.
1043
+
1044
+ ### 21.3 What a time-stamp fixes
1045
+
1046
+ Every counted time-stamp of a seal is taken, of either kind, and the
1047
+ earliest time that any of them states is the time by which every entry
1048
+ before that seal existed. (A block time-stamp states its block's time and
1049
+ 7,200 seconds: section 21.4.) Two cases are set apart. In both, a block
1050
+ states a time far behind the true time, and a service settles it.
1051
+
1052
+ 1. Where a seal has a counted time-stamp from a service, a counted block
1053
+ time-stamp that states a time more than 300 seconds before the seal's
1054
+ own `when`, even with its 7,200 seconds, is set aside: it gives no
1055
+ time, and rule 7 of section 21.2 is not applied to it. A checker MUST
1056
+ then say that the two do not agree.
1057
+ 2. A counted block time-stamp that states a time, even with its 7,200
1058
+ seconds, more than 300 seconds before the latest time that a counted
1059
+ time-stamp from a service gave any seal before this one is set aside
1060
+ in the same way, whether or not a service's time-stamp stands beside
1061
+ it. This seal covers that seal's line, time-stamp included, so it
1062
+ cannot have existed by then. A checker MUST say that the block
1063
+ time-stamp was set aside. Among the pages of a Show, and for the seal
1064
+ that comes with a Show, the seals before it are those among the
1065
+ pages.
1066
+
1067
+ A time-stamp is counted only if all
1068
+ three signatures of its seal were checked on that device; where they
1069
+ were not, a checker MUST say that the time-stamp was not counted, and
1070
+ MUST NOT report any date against it. More exactly, it shows
1071
+ that the content of the seal existed then: the time-stamp is made over
1072
+ the seal's fingerprint, which covers its content and not its signatures.
1073
+
1074
+ The time that counts for an entry is the earliest that the counted
1075
+ time-stamps of any seal after it state: every seal after an entry covers
1076
+ it. (In section 22, only the seals before the cancellation are taken.) A
1077
+ checker
1078
+ MUST report an entry that states a time (its own `when`, or the `when` of
1079
+ a countersignature or an approval on the same line) more than 300 seconds
1080
+ later than that (`dated-after-stamp`). The same holds for each page of a
1081
+ Show that comes with a seal (section 11).
1082
+
1083
+ The earliest time that a counted time-stamp from a service gives a seal
1084
+ MUST NOT be more than 300 seconds earlier than the latest such time that
1085
+ a service gave any seal before it (`time-went-backwards`). So the times
1086
+ cannot step backwards a little at a time. A block time-stamp is never
1087
+ reported under this rule: it is made hours after its seal, and one that
1088
+ states an earlier time is set aside (the second case above).
1089
+
1090
+ A checker that shows an entry's times MUST keep two apart: the time by
1091
+ which a seal after the entry shows that it existed, and the time that a
1092
+ seal's or a cancellation's own counted time-stamps give it. A
1093
+ cancellation does not count from the time of a seal after it (section
1094
+ 22). A checker MUST NOT show a time of the second kind for a seal or a
1095
+ cancellation that did not pass its check.
1096
+
1097
+ A seal shown as a single page of a Show cannot be compared with the
1098
+ entries before it. A checker MUST confirm that its `size` is the page's
1099
+ own place in the book (`seal-mismatch`), MUST say that it could not be
1100
+ compared, and MUST NOT credit its time-stamp to any other page.
1101
+
1102
+ Its dates are still held against the other pages. Each page is shown to
1103
+ be in the book at its place, so where the dates do not fit, the whole
1104
+ book would fail its check one way or another. A checker MUST report:
1105
+
1106
+ - the seal, if a page that comes before it in the book states a time
1107
+ more than 300 seconds after the seal's counted time-stamp
1108
+ (`dated-after-stamp`). The finding is given for the seal and not for
1109
+ that page: either the page's date is not as it says, or the seal does
1110
+ not fit the entries before it, and single pages cannot show which;
1111
+ - the seal, if its `when` is more than 300 seconds earlier than a time
1112
+ that a page before it states, where that page is not one of the first
1113
+ case (`time-went-backwards`);
1114
+ - a seal, among the pages or come with the Show, whose `when` is earlier
1115
+ than that of a seal among the pages that comes before it in the book,
1116
+ or whose counted time-stamp from a service is more than 300 seconds
1117
+ earlier than such a seal's (`time-went-backwards`);
1118
+ - a seal, among the pages or come with the Show, that does not fit the
1119
+ chain of seals as far as the pages show it (`seal-chain-broken`): it
1120
+ has no `previous` though a seal among the pages comes before it; or
1121
+ its `previous` names a seal among the pages that does not come before
1122
+ it, or that has another seal among the pages between the two.
1123
+
1124
+ A checker MUST say how far the last counted time-stamp reaches, and that
1125
+ entries after it are not time-stamped.
1126
+
1127
+ What a seal and a time-stamp do not fix: the last seal of a book, with
1128
+ everything after it, can be removed, and what is left still checks. Only
1129
+ a copy of that seal, or of its top fingerprint and number of entries,
1130
+ held by someone else shows it. And a time-stamp service signs with a
1131
+ method of today's kind.
1132
+
1133
+ ### 21.4 A block time-stamp
1134
+
1135
+ A second kind of time-stamp rests on no signature. It is a proof that
1136
+ the seal's fingerprint was written into a block of a public blockchain.
1137
+ The chain is used purely as a clock: no coin, no wallet, no account and
1138
+ no payment is involved in making such a proof or in checking one.
1139
+
1140
+ In `stamps` a block time-stamp is the object `{"block": header, "proof":
1141
+ proof}`, each in base64url:
1142
+
1143
+ - `proof` is a proof file of the open format OpenTimestamps, version 1,
1144
+ of at most 12,288 bytes;
1145
+ - `block` is the 80-byte header of a block of the Bitcoin blockchain;
1146
+ one of any other length is refused (`stamp-bad-data`).
1147
+
1148
+ A proof file holds steps that lead from a fingerprint to a value, and
1149
+ statements about values. A checker MUST confirm all of these, and
1150
+ otherwise report a problem:
1151
+
1152
+ 1. The file begins with these 31 bytes, in hex: `00 4f 70 65 6e 54 69 6d
1153
+ 65 73 74 61 6d 70 73 00 00 50 72 6f 6f 66 00 bf 89 e2 e8 84 e8 92
1154
+ 94`; then the byte `01` (the version); then the byte `08` (SHA-256);
1155
+ then 32 bytes, the fingerprint that was stamped (`stamp-bad-data`).
1156
+ 2. Then comes everything that follows from that value. Each thing is a
1157
+ statement or a step, and each but the last is preceded by the byte
1158
+ `ff` (`stamp-bad-data`):
1159
+ - A **statement** is the byte `00`, 8 bytes that say its kind, a
1160
+ length, and that many bytes (at most 8,192). The kind `05 88 96 0d
1161
+ 73 d7 19 01` says "this value is the Merkle root of the block with
1162
+ this number"; its bytes are the block's number and nothing more. A
1163
+ statement of any other kind is passed over.
1164
+ - A **step** makes a new value, and is followed by everything that
1165
+ follows from the new value. The byte `08`: the SHA-256 of the
1166
+ value. The byte `f0`, a length and that many bytes: the value with
1167
+ those bytes joined after it. The byte `f1`, likewise: joined before
1168
+ it. A step joins 1 to 4,096 bytes, and no value is longer than 4,096
1169
+ bytes. Any other step is refused. (The format also has steps for
1170
+ SHA-1, RIPEMD-160 and Keccak-256, and two it no longer uses. Proofs
1171
+ made today do not use them.)
1172
+ - No more than 255 steps follow one another, as the format's own reader allows.
1173
+ 3. A number (a length, a block's number) is written seven bits to a
1174
+ byte, lowest first, with the top bit of a byte saying that another
1175
+ follows; in its shortest form only, and in at most 5 bytes
1176
+ (`stamp-bad-data`).
1177
+ 4. Nothing follows the end (`stamp-bad-data`).
1178
+ 5. The fingerprint stamped is this seal's fingerprint
1179
+ (`stamp-wrong-data`).
1180
+ 6. A statement about a block stands at a value of 32 bytes that equals
1181
+ bytes 36 to 67 of the header in `block`, its Merkle root
1182
+ (`stamp-invalid`).
1183
+
1184
+ **Whom to trust is the checker's choice.** The fingerprint of a block is
1185
+ SHA-256 taken twice over its 80-byte header, with the bytes then put in
1186
+ reverse order, in hex: 64 characters, as it is written wherever blocks
1187
+ are listed. The person checking gives the fingerprints of the blocks
1188
+ they trust to be part of the chain, at most 100,000. A block time-stamp counts only if it
1189
+ leads to one of those. One that leads to any other block MUST be shown,
1190
+ with the block's fingerprint, and MUST NOT be counted. The block's
1191
+ number in the proof is only what the proof says: nothing checks it, and
1192
+ a checker that shows it MUST say so.
1193
+
1194
+ **Finding which blocks to trust.** A checker MAY take the blocks it
1195
+ trusts from a chain of block headers that it checks itself, from the
1196
+ chain's first block, by the rules every Bitcoin node applies to headers
1197
+ (each names the block before it; its double SHA-256 meets the target its
1198
+ `bits` state; that target follows the difficulty rule; its time is later
1199
+ than the middle of the eleven before it, and not more than two hours
1200
+ ahead of the checker's clock; its version is no lower than the upgrades
1201
+ of 2013 and 2015 ask from their blocks on). Such a checker MUST also
1202
+ require that the chain hold blocks known to be part of it, at their
1203
+ places, and reach the last of them; MUST refuse, after the last of them,
1204
+ a target more than four times easier than that block's; and MUST count a
1205
+ block only with at least six blocks after it. This library's checker does so with `--headers`; the known blocks are
1206
+ listed in `src/headers.js`. A chain file holds the 80-byte headers one
1207
+ after another, from the chain's first block. Nothing in a record
1208
+ changes.
1209
+
1210
+ **The time.** The time a block states is bytes 68 to 71 of its header: a
1211
+ whole number of seconds since the start of 1970, lowest byte first. It
1212
+ is set by whoever made the block, and is right only to within about two
1213
+ hours. Which way that looseness is taken depends on what is asked, so
1214
+ that it never works in favour of whoever is being checked:
1215
+
1216
+ - For a **seal**, a counted block time-stamp is taken to state that the
1217
+ seal existed by the block's stated time **and 7,200 seconds**. That is
1218
+ the time used in section 21.3, and for a stub in section 22.
1219
+ - For a **cancellation** (section 22), which may carry block time-stamps
1220
+ in the same way, over the cancellation's fingerprint, a block
1221
+ time-stamp gives the block's stated time **less 7,200 seconds**: the
1222
+ earliest the proof could have been made. A later time would excuse
1223
+ stubs made after the person cancelled. There is one bound. The time
1224
+ given is never earlier than the cancellation's own `when`. By the
1225
+ person's own signed word the cancellation was not made before its
1226
+ `when`, so a stub shown to have existed by then was made before the
1227
+ person cancelled. So a cancellation cannot be moved back in time by
1228
+ having it put into a block before the date it gives. Where the block's
1229
+ stated time and 7,200 seconds is more than 300 seconds before the
1230
+ cancellation's `when`, the two do not agree. With no counted
1231
+ time-stamp from a service beside it, the cancellation is dated after
1232
+ its time-stamp and does not pass (`dated-after-stamp`). With one, the
1233
+ service settles it, and a checker MUST say that the two do not agree.
1234
+
1235
+ A checker MUST show the time the block states, say that it is right only
1236
+ to within two hours, and for a cancellation show the time T it used.
1237
+
1238
+ A block that states a time more than two hours behind the true time,
1239
+ which the chain's rules allow in rare cases, would make an honest seal
1240
+ or entry read as dated after its time-stamp. A counted time-stamp from a
1241
+ service beside it settles such a case: the service's time is then the
1242
+ one used. A checker MUST then say that the block time-stamp states a
1243
+ time more than two hours before the seal's own date: the other reading
1244
+ is that the seal existed before the date it gives. A counted time-stamp
1245
+ from a service on a seal earlier in the book settles it too (section
1246
+ 21.3, the second case): without that, such a block would show the
1247
+ entries of a later seal to have existed earlier than they did.
1248
+
1249
+ What a block time-stamp does not fix: that the header is that of a real
1250
+ block. The person who names a block vouches for that, having compared
1251
+ its fingerprint with sources they trust. A proof is complete only one to
1252
+ several hours after it is asked for, so it is an addition to a
1253
+ time-stamp from a service, not a replacement.
1254
+
1255
+ ## 22. Cancelling a slip
1256
+
1257
+ The person who signed a slip can end it early, with the same passkey.
1258
+
1259
+ Content: `{"id": unique number, "slip": the slip's fingerprint, "type":
1260
+ "provared.cancellation.v0", "when": a time}`. It is signed as a slip is
1261
+ (sections 4.2 and 4.3), with the cancellation label of section 3.2, and
1262
+ checked against the `issuer` of the slip it names
1263
+ (`cancellation-invalid`). The slip MUST be earlier in the book
1264
+ (`slip-missing`).
1265
+
1266
+ The entry that holds a cancellation MAY hold `stamps`: time-stamps over
1267
+ the cancellation's fingerprint, checked as section 21.2 sets out. The
1268
+ person can have these made at once, without waiting for the recorder.
1269
+ A time-stamp is counted only if the passkey signature of the
1270
+ cancellation, and of its slip, was checked on that device; where it was
1271
+ not, a checker MUST say that the time-stamp was not counted, and MUST
1272
+ NOT report any date against it, as for a seal (section 21.3).
1273
+
1274
+ What a checker reports, as `after-cancellation` (section 8):
1275
+
1276
+ 1. Every stub under the slip that comes after the cancellation in the
1277
+ book.
1278
+ 2. Where the cancellation has a counted time-stamp, at a time T: every
1279
+ stub under the slip that comes before the cancellation in the book,
1280
+ unless a counted time-stamp, on a seal that is before the cancellation
1281
+ in the book and covers the stub, states a time not more than 300
1282
+ seconds after T.
1283
+
1284
+ The second rule is strict on purpose. The time an agent writes into a
1285
+ stub is its own word, so an agent could otherwise escape a cancellation
1286
+ by writing an earlier time. A stub made honestly just before a
1287
+ cancellation, and not yet sealed, is reported as "not shown to have
1288
+ existed before the slip was cancelled", which is exactly what the record
1289
+ can and cannot show. A recorder that seals often keeps this rare.
1290
+
1291
+ Every cancellation of a slip that passes its check counts. The first
1292
+ rule is applied from the first of them in the book. The second rule is
1293
+ applied with the earliest time T that a counted time-stamp gives any of
1294
+ them, to the stubs that come before that cancellation in the book. So
1295
+ the order in which whoever keeps the book places two cancellations
1296
+ changes nothing.
1297
+
1298
+ **The time T.** Every counted time-stamp beside a cancellation is taken,
1299
+ of either kind, and T is the earliest time that any of them gives. A
1300
+ time-stamp from a service gives the time it states. A block time-stamp
1301
+ gives the time that section 21.4 sets out. So a later time-stamp put
1302
+ beside an earlier one changes nothing. (Section 21.3 sets out which
1303
+ time counts for a seal.)
1304
+
1305
+ Single pages of a Show apply the first rule only, by the place each page
1306
+ has in the book: single pages cannot show which seal covered a stub. A
1307
+ checker MUST say so where a cancellation among the pages has a counted
1308
+ time-stamp.
1309
+
1310
+ The time-stamps stand beside the cancellation, not inside what the
1311
+ passkey signed. Whoever keeps the book can therefore put a later
1312
+ time-stamp in the place of an earlier one, and no check can show that.
1313
+ Where the time T is more than 300 seconds after the cancellation's own
1314
+ `when`, a checker MUST point it out. (A later time-stamp beside a prompt
1315
+ one leaves no such gap, and changes nothing.) The person SHOULD keep
1316
+ their own copy of the cancellation, with its time-stamp.
1317
+
1318
+ A cancellation shows when the person signed it and had it time-stamped.
1319
+ It does not show that the agent, or whoever keeps the book, was told. A
1320
+ person can keep a cancellation back and hand it over later: every stub
1321
+ made in between is then reported, though the check before acting allowed
1322
+ each. Where a checker is handed a copy that the book does not hold, it
1323
+ cannot show whether the book's keeper left it out or was never given
1324
+ it, and MUST say so. An acknowledgement from the agent's side (section
1325
+ 26), handed over with the copy, shows that it was given it, and when.
1326
+
1327
+ **The person's own copy.** A checker MAY be handed, beside a book, up to
1328
+ 16 cancellations that the person kept, each as the entry it would be in
1329
+ a book: `{"cancellation": cancellation record}`, with or without
1330
+ `"stamps"`, and with or without `"acknowledgements"` (section 26). Each
1331
+ is checked as a cancellation in the book is: against the
1332
+ `issuer` of the slip it names, which MUST be in the book
1333
+ (`slip-missing`, `cancellation-invalid`), and its time-stamps as section
1334
+ 21.2 sets out. A copy that does not pass is a problem with the check as
1335
+ a whole: it is never set aside silently. The same cancellation MUST NOT
1336
+ be handed over twice (`bad-field`). For a copy that passes:
1337
+
1338
+ 1. where a counted time-stamp gives it a time T, every stub under the
1339
+ slip, wherever it stands in the book, is reported as
1340
+ `after-cancellation`, unless a counted time-stamp on a seal that
1341
+ covers the stub states a time not more than 300 seconds after T;
1342
+ 2. the check before acting (section 20) allows nothing under the slip;
1343
+ 3. a checker MUST say whether the book holds the same cancellation.
1344
+
1345
+ So a cancellation counts even where whoever keeps the book left it out,
1346
+ and the person's own time-stamp counts even where the book holds the
1347
+ cancellation with a later one. A copy with no counted time-stamp cannot
1348
+ be placed in time, and no stub is reported because of it. Single pages
1349
+ of a Show cannot use a copy, and a checker MUST say so.
1350
+
1351
+ ## 23. Vouching for a name, and withdrawing
1352
+
1353
+ A name in a record is a label. A vouching record lets an organisation
1354
+ stand behind one: it states that a key belongs to a name.
1355
+
1356
+ Content:
1357
+
1358
+ | Member | Meaning | Form |
1359
+ |---|---|---|
1360
+ | `type` | The kind of record | `provared.vouching.v0` |
1361
+ | `id` | Unique number | Section 3.7 |
1362
+ | `by` | The organisation that vouches | `{"keys": key set, "name": text}` |
1363
+ | `for` | Whom it vouches for | One of the four forms below |
1364
+ | `validFrom`, `validUntil` | When the statement holds | Times; the second later than the first |
1365
+ | `when` | When it was made | A time |
1366
+
1367
+ | `for` | Form |
1368
+ |---|---|
1369
+ | A person | `{"key": the passkey's public key, "kind": "person", "name": text}` |
1370
+ | An agent | `{"keys": key set, "kind": "agent", "name": text}` |
1371
+ | A service | `{"keys": key set, "kind": "service", "name": text}` |
1372
+ | A recorder | `{"keys": the three keys, "kind": "recorder", "name": text}` |
1373
+
1374
+ It is signed with the key set in `by`, with the vouching labels of
1375
+ section 3.2.
1376
+
1377
+ **What it vouches for.** A vouching record stands behind a name in a
1378
+ later record only if all of these hold: it is earlier in the book; it
1379
+ passed its own check; it has not been withdrawn earlier in the book; its
1380
+ `for.kind` fits the place of the name (`person` for the issuer of a
1381
+ slip; `agent` for its agent, and for the helper agent a pass names in
1382
+ `to`; `service` for one of its services; `recorder` for the recorder of
1383
+ a seal); its key or keys are exactly the key or keys that record gives;
1384
+ its `for.name` is exactly that name; and it is in force for the whole
1385
+ time of that record. For a slip or a pass that means: its `validFrom` is
1386
+ not later than the record's `validFrom`, and its `validUntil` is not
1387
+ earlier than the record's `validUntil`. For a seal: the seal's `when`,
1388
+ and the time of a counted time-stamp on the seal where there is one, are
1389
+ not before its `validFrom` and are before its `validUntil`.
1390
+
1391
+ A covered name (section 24) that was not revealed is vouched for by
1392
+ nobody. Where several vouching records stand behind one name, a checker
1393
+ shows one that counts, if there is one.
1394
+
1395
+ **Whom to trust is the checker's choice.** The person checking gives the
1396
+ fingerprint of the key set (section 21.1) of each organisation whose
1397
+ vouching they trust. Only a vouching record signed by one of those
1398
+ counts. A checker MUST show a name as vouched for only then, with the
1399
+ fingerprint of the organisation's key set. A vouching record from any
1400
+ other organisation MUST be shown as not counted.
1401
+
1402
+ **Withdrawing.** Content: `{"id": unique number, "type":
1403
+ "provared.withdrawal.v0", "vouching": the vouching record's fingerprint,
1404
+ "when": a time}`. It is signed with the key set of the organisation that
1405
+ made the vouching record, with the withdrawal labels: only that
1406
+ organisation can withdraw. The vouching record MUST be earlier in the
1407
+ book (`vouching-missing`). From the withdrawal's place in the book
1408
+ onwards, the vouching record stands behind nothing.
1409
+
1410
+ What a vouching record does not show: that the organisation checked well,
1411
+ or that the organisation is who its own name says. The trust ends at keys
1412
+ the person checking chose.
1413
+
1414
+ ## 24. Covered fields
1415
+
1416
+ A slip can be shown with its names and its purpose hidden, while
1417
+ everything about it still checks. The method is that of the standard
1418
+ "Selective Disclosure for JSON Web Tokens" (RFC 9901): the same
1419
+ disclosures, the same fingerprints, the same checking steps. A slip uses
1420
+ less than the standard allows, as this section sets out, so that no two
1421
+ readers can be shown slips that differ in anything a checker compares.
1422
+
1423
+ **What may be covered.** In a slip: `issuer.name`, `agent.name`, the
1424
+ `name` of each service in `with`, and `purpose`. Nothing else, and
1425
+ nothing in any other kind of record. An item of a list MUST NOT be
1426
+ covered anywhere in a slip (the form `{"...": fingerprint}` of RFC 9901,
1427
+ section 4.2.4.2; `cover-invalid`): a covered limit, condition, action,
1428
+ service or key would give one reader a different slip from another.
1429
+
1430
+ **How a field is covered** (RFC 9901, section 4.2). A disclosure is the
1431
+ JSON list `[salt, name, value]`, written in base64url, where the salt is
1432
+ text holding at least 128 random bits. Its fingerprint is the SHA-256
1433
+ hash of the characters of that base64url text, in base64url. The field
1434
+ is taken out of its object, and the fingerprint is added to a list named
1435
+ `_sd` in the same object. Every member of such a list MUST be a SHA-256 fingerprint in base64url,
1436
+ 43 characters (`cover-invalid`). In a slip, each such list holds exactly
1437
+ one fingerprint: that of the one field that may be covered in that
1438
+ object. A decoy fingerprint, which the
1439
+ standard allows, is not accepted, and neither is a list that stands
1440
+ beside the field it would stand in for (`bad-field`). So a field is
1441
+ absent only where its fingerprint stands in its place.
1442
+ A slip's content holds `"_sd_alg": "sha-256"` at the top where it covers
1443
+ anything, and not otherwise (`bad-field`); no other fingerprint method
1444
+ is accepted.
1445
+
1446
+ The person's passkey signs the content in this covered form. The
1447
+ fingerprint of the slip, the chain and the tree are worked out from the
1448
+ covered form, so they are the same for every reader.
1449
+
1450
+ **Where disclosures are kept.** Beside the record, not inside a line of
1451
+ the book: a line is a leaf of the tree, and must be the same for every
1452
+ reader. A page of a Show MAY hold `"disclosures"`, a list of 1 to 64
1453
+ disclosures for the slip on that page; a page that is not a slip MUST
1454
+ NOT hold it (`cover-invalid`). A checker MAY also be handed disclosures
1455
+ by the fingerprint of the slip they belong to; where no such slip is
1456
+ among the entries, they are not used and a checker MUST say so. Where a
1457
+ page holds disclosures and others are handed over for the same slip, all
1458
+ are used together, and one given both ways counts once.
1459
+
1460
+ **Checking** (RFC 9901, section 7.1, steps 3 to 5). A checker MUST:
1461
+
1462
+ 1. work out the fingerprint of each disclosure handed over;
1463
+ 2. for each fingerprint in an `_sd` list that matches a disclosure, put
1464
+ the named field back in that object;
1465
+ 3. refuse (`cover-invalid`) if a fingerprint appears twice in
1466
+ the content; if a disclosure matches nothing; if a disclosure is
1467
+ handed over twice; if a disclosure is not a list of a salt, a name and
1468
+ a value; if its name is `_sd`, `...` or `_sd_alg`; if its name is
1469
+ already a field of that object; if an item of a list is covered; or if
1470
+ a disclosure, once its base64url is decoded, is not JSON in the
1471
+ canonical form of section 3.4;
1472
+ 4. refuse the record (`bad-field`) if an `_sd` list stands anywhere other
1473
+ than in the slip itself, its `issuer`, its `agent` or one of its
1474
+ services; if such a list does not hold exactly one fingerprint; if the
1475
+ field it stands in for is there as well; if a revealed field is not
1476
+ the one that may be covered there; or if `_sd_alg` is absent where a
1477
+ field is covered, or present where none is;
1478
+ 5. then check the slip as section 4 sets out, with every revealed field
1479
+ in place. A field that may be covered is absent exactly where its
1480
+ fingerprint stands in its place and no disclosure for it was handed
1481
+ over.
1482
+
1483
+ **What a slip is does not depend on what is handed over with it.** Where
1484
+ a slip fails step 3, 4 or 5 with the disclosures handed over, a checker
1485
+ MUST check it again with no disclosure. If it then passes, the fault
1486
+ lies in the disclosures: they are not used, every field they would have
1487
+ revealed stays covered, the slip and the stubs under it are checked as
1488
+ they would be with no disclosure, and the checker MUST report the
1489
+ problem as one with what was handed over, so that the check as a whole
1490
+ is not a pass. Otherwise the signer of a slip could make it sound for a
1491
+ reader with no disclosure and unsound for a reader with one. Disclosures
1492
+ handed over in any other form than `{fingerprint of a slip:
1493
+ [disclosures]}` are refused (`bad-field`).
1494
+
1495
+ A fingerprint in an `_sd` list with no disclosure is left alone: the
1496
+ field is covered. A checker MUST show that fields are covered, and how
1497
+ many, and MUST NOT show a covered field's place as empty.
1498
+
1499
+ The standard allows any JSON in a disclosure. A slip's disclosures are
1500
+ narrower, as step 3 says: loose JSON (stray spaces, a repeated name, an
1501
+ unusual escape) could be read in two ways by two checkers.
1502
+
1503
+ A checker MUST treat every member name as a plain name. A member named
1504
+ `__proto__`, for example, is a member like any other: in a slip it is
1505
+ refused as unknown (`bad-field`), and nothing is ever taken from it.
1506
+
1507
+ The standard's key binding (its section 4.3) is not used: a Provared
1508
+ record is not presented by a holder who must prove possession of a key.
1509
+
1510
+ ## 25. Passing a slip on to a helper agent
1511
+
1512
+ An agent may hand part of its permission to a helper agent, if the slip
1513
+ allows it. The slip's `passes` says how many times in a row: 1 means the
1514
+ slip's agent may pass on to a helper; 2 means that helper may pass on
1515
+ once more; and so on, up to 10. A slip with no `passes` may not be passed on.
1516
+
1517
+ Content of a pass:
1518
+
1519
+ | Member | Meaning | Form |
1520
+ |---|---|---|
1521
+ | `type` | The kind of record | `provared.pass.v0` |
1522
+ | `id` | Unique number | Section 3.7 |
1523
+ | `slip` | The slip | The slip's fingerprint |
1524
+ | `from` | The pass its writer itself acts under. Absent when the writer is the slip's own agent | That pass's fingerprint |
1525
+ | `to` | The helper agent | `{"keys": key set, "name": text}` |
1526
+ | `actions` | What the helper may do | A list of 1 to 64 action names, none repeated |
1527
+ | `limits` | Limits for the helper | A list of 0 to 64 limits, as in a slip (section 4.1) |
1528
+ | `validFrom`, `validUntil` | When the pass holds | Times; the second later than the first |
1529
+ | `when` | When it was written | A time |
1530
+
1531
+ A pass is signed with the key set of the agent that passes on: the
1532
+ slip's `agent.keys`, or, where it names `from`, the `to.keys` of that
1533
+ pass. A pass MUST come after its slip in the book, and after the pass it
1534
+ names in `from` (`pass-missing`), and that pass MUST be under the same
1535
+ slip (`pass-mismatch`). A pass MUST NOT be the eleventh in a row
1536
+ (`pass-too-deep`): no slip can allow more than ten, and the rule lets
1537
+ every stub be compared with every pass above its own at a small, fixed
1538
+ cost. Ten is a first-draft number, taken from the upper number commonly
1539
+ set for chains of delegated access between services.
1540
+
1541
+ A helper's stub names its pass in `pass`, and is signed with the
1542
+ `to.keys` of that pass. The stubs under one pass form a chain of their
1543
+ own (section 7).
1544
+
1545
+ What a checker reports about a pass:
1546
+
1547
+ | Code | Shown when |
1548
+ |---|---|
1549
+ | `pass-not-allowed` | The pass is one more in a row than the slip's `passes` allows. Every later pass that names it, and every stub under any of them, is reported too |
1550
+ | `pass-wider` | An action in `actions` is not one its writer holds (the slip's `actions`, or the `actions` of the pass in `from`), or `validFrom` is earlier, or `validUntil` later, than its writer's own |
1551
+ | `outside-valid-time` | `when` is outside the time its writer's own permission holds |
1552
+ | `after-cancellation` | The person had cancelled the slip (section 22) |
1553
+
1554
+ What a checker reports about a helper's stub:
1555
+
1556
+ 1. Everything of section 8, compared with the **slip**, exactly as for
1557
+ the slip's own agent. The slip's totals, counts and periods take in
1558
+ the stubs of the agent and of every helper together. The slip's
1559
+ conditions and stated rules hold for a helper too.
1560
+ 2. Also the findings of section 8 compared with the **pass**, taking its
1561
+ `actions`, its `limits` and its times as a slip's, with totals of its
1562
+ own.
1563
+ 3. And the same compared with **every pass above it**: the pass that its
1564
+ own pass names in `from`, and so on up. The totals of a pass take in
1565
+ the stubs written under it and under every pass handed on from it.
1566
+
1567
+ A finding with the same code as one that the slip, or a pass nearer the
1568
+ stub, already gave for the stub is not given twice.
1569
+
1570
+ A pass's limits are not compared with the limits of the slip, or of the
1571
+ pass above it. They need not be: the limits of the slip and of every
1572
+ pass above always hold for a helper, so passing on cannot widen them.
1573
+
1574
+ ## 26. Acknowledging a cancellation
1575
+
1576
+ A cancellation shows when the person signed it. It does not show that
1577
+ the agent's side was told (section 22). An acknowledgement closes that
1578
+ gap from the other side: the agent's own software states that it was
1579
+ handed the cancellation, and when. The person keeps it with their copy
1580
+ of the cancellation.
1581
+
1582
+ Content:
1583
+
1584
+ | Member | Meaning | Form |
1585
+ |---|---|---|
1586
+ | `type` | The kind of content | `provared.acknowledgement.v0` |
1587
+ | `id` | A unique number | Section 3.7 |
1588
+ | `slip` | The slip that was cancelled | A fingerprint |
1589
+ | `cancellation` | The cancellation that was handed over | A fingerprint |
1590
+ | `pass` | Optional. For a helper agent: the pass it acts under | A fingerprint |
1591
+ | `when` | When the cancellation was handed over, as the agent's side states it | A time |
1592
+
1593
+ It is signed as a stub is (section 5.2), with the acknowledgement labels
1594
+ of section 3.2: with the two keys of the agent the slip names or, where
1595
+ it holds `pass`, with the `to.keys` of that pass
1596
+ (`signature-invalid`). So it speaks for one agent: the slip's own, or
1597
+ one helper.
1598
+
1599
+ **In a book.** The slip MUST be earlier in the book (`slip-missing`),
1600
+ and so MUST the pass, under the same slip (`pass-missing`,
1601
+ `pass-mismatch`). The cancellation it names MUST be earlier in the book,
1602
+ MUST cancel the same slip, and MUST have passed its own check
1603
+ (`cancellation-not-found`): that includes a cancellation which a later
1604
+ seal's time-stamp shows to be dated later than it existed (section
1605
+ 21.3). Among the pages of a Show, the slip, the
1606
+ pass and the cancellation MUST be among the pages. An acknowledgement in
1607
+ a book changes nothing that section 22 reports: every stub after the
1608
+ cancellation is reported already.
1609
+
1610
+ No rule ties its `when` to the cancellation's `when`. Each is one
1611
+ side's own word, and the two clocks may differ: an acknowledgement may
1612
+ be dated before the date the person's device gave.
1613
+
1614
+ **Handed over with the person's own copy.** The entry a checker is
1615
+ handed for the person's own copy of a cancellation (section 22) MAY hold
1616
+ `"acknowledgements"`: a list of 1 to 4 acknowledgement records, none
1617
+ twice (`bad-field`). Each MUST name that cancellation and its slip
1618
+ (`acknowledgement-mismatch`), and is checked against the keys of the
1619
+ slip's agent, or of the helper of a pass that the book holds
1620
+ (`pass-missing`, `signature-invalid`). One that does not pass is a
1621
+ problem with the check as a whole, and is not used; it MUST be reported,
1622
+ never set aside silently. The copy of the cancellation itself is still
1623
+ used: an acknowledgement that does not pass takes nothing from what the
1624
+ cancellation shows. One that this device could not check is not used,
1625
+ and a checker MUST say so; that includes every acknowledgement beside a
1626
+ copy, or under a slip, that this device could not confirm. For each
1627
+ acknowledgement that passes:
1628
+
1629
+ 1. a checker MUST show it: who acknowledged (the slip's agent, or which
1630
+ helper), and the time it states, as the agent's side's own word;
1631
+ 2. these are reported as `after-cancellation`, whether or not the copy
1632
+ has a counted time-stamp:
1633
+ - every stub in that agent's own chain (section 7) whose `when` is
1634
+ later than the acknowledgement's `when`;
1635
+ - every pass that agent wrote (section 25) whose `when` is later
1636
+ than the acknowledgement's `when`, every pass handed on from such
1637
+ a pass, and every stub under any of them.
1638
+
1639
+ By the agent's own dates each was made after the agent's side was
1640
+ told. A checker MUST word this finding so that it can be told apart
1641
+ from the finding of section 22 ("not shown to have existed before
1642
+ the slip was cancelled");
1643
+ 3. the rule of section 22 is applied first, for every copy handed over,
1644
+ whatever order they were handed over in. A stub that it reports keeps
1645
+ that finding, which rests on an outside time-stamp; where rule 2
1646
+ applies to the stub as well, the finding says so in addition;
1647
+ 4. where the book does not hold the cancellation, a checker MUST say
1648
+ that the agent's side acknowledged it, and when. It was then left out
1649
+ of the book, or was still to be written into it when the copy of the
1650
+ book was made.
1651
+
1652
+ What an acknowledgement does not show: when the person cancelled; that
1653
+ a helper agent was told, where only the slip's own agent acknowledged
1654
+ (a helper that held its pass before then is not reported under rule 2);
1655
+ or anything about a stub dated at or before its `when`. Whoever signs
1656
+ an acknowledgement SHOULD NOT date it before the last stub of its own
1657
+ chain, nor before a pass that it handed on: either may be dated a little
1658
+ ahead of the signer's clock, and would otherwise read as made after the
1659
+ agent's side was told. Where a copy holds several acknowledgements,
1660
+ what each agent did itself after it was told is settled first, for every
1661
+ acknowledgement, and then what was done under a pass handed on late: so
1662
+ the wording of a finding does not depend on their order. Both dates in
1663
+ rule 2 are the agent's own word: an agent that writes earlier dates into
1664
+ its stubs escapes rule 2, and is caught only by the time-stamp rule of
1665
+ section 22. Nothing obliges an agent's side to acknowledge: a
1666
+ cancellation with no acknowledgement shows nothing about whether the
1667
+ agent's side was told.
1668
+
1669
+ ---
1670
+
1671
+ Copyright 2026 Pavel Izmaylov. This document is licensed under the
1672
+ Creative Commons Attribution 4.0 International licence.