provared 0.4.0 → 0.6.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.
@@ -91,6 +91,20 @@ follows the checking steps of the Web Authentication standard.
91
91
  section 6b. Slips should still be short-lived.
92
92
  - Who the issuer is. The slip proves which key signed, not whose key it
93
93
  is.
94
+ - Against a page that has the passkey sign a record dressed as a sign-in.
95
+ A passkey signs only a challenge, and the challenge for a slip, an
96
+ approval or a cancellation is the fingerprint of the record, which the
97
+ person cannot read on the device's prompt. Any page at an origin under
98
+ the slip's `rpId` (the website's own operator, a script running on one
99
+ of its pages, or the operator of any subdomain) can hand the device the
100
+ fingerprint of a record it wrote as an ordinary sign-in challenge: the
101
+ client data of a sign-in and of a record have the same shape, and the
102
+ person sees a sign-in prompt. No device and no page need be broken into.
103
+ The checker compares the origin and the rpId only with what the slip
104
+ itself says. So a passkey that signs records should be registered to a
105
+ relying party (an `rpId`) used for nothing else, and the page that asks
106
+ for the signature should show the record first. The checker has no
107
+ option yet by which a reader names the origin they expect.
94
108
 
95
109
  ## 4. The Stub and the countersignature
96
110
 
@@ -123,6 +137,60 @@ fingerprint.
123
137
  - The documents themselves. A stub holds fingerprints of documents, not
124
138
  the documents. Whoever keeps the documents must keep them.
125
139
 
140
+ **A stub bound to the other system's own record of the call.** Where the
141
+ other side will not countersign, a stub may name, under a reserved name
142
+ (format description, section 27), the fingerprint of the identifier the
143
+ platform gave the call (`provared.event-id`), of one the agent's side
144
+ chose and sent (`provared.trace-id`, `provared.request-id`), of part
145
+ of the request and the answer (`provared.http-request`: the method, the
146
+ address and the body; `provared.http-response`: the status and the
147
+ body; no header is covered), or of the error the agent was given
148
+ (`provared.error`).
149
+
150
+ - *What it shows.* Someone who holds the platform's own log can work the
151
+ fingerprint out again and match the two records, without either
152
+ side's help. For an identifier, the two speak of one call. An agent's
153
+ side that later claims another identifier for the call, or a platform
154
+ that later shows another, is caught by the mismatch.
155
+ - *Only an identifier picks out one call.* A request, an answer, the
156
+ arguments or an error shows only that the content matches: identical
157
+ requests, and identical answers (many a `200` with the body `{}`),
158
+ share one fingerprint, so a match with one of them does not show that
159
+ it was the same call. Only `provared.trace-id`, `provared.request-id`
160
+ and `provared.event-id` are meant to pick out one call, and only they
161
+ may be named more than once in a stub.
162
+ - *The body's bytes* are what RFC 9530 digests: the content after any
163
+ content coding (such as gzip) and before any transfer coding. A
164
+ platform that logs the decoded body of a message sent compressed will
165
+ not match.
166
+ - *A trace-id's form is not checked.* The W3C standard writes it as 32
167
+ lower-case hexadecimal characters, but any text is fingerprinted as
168
+ given.
169
+ - *What it does not show.* That the call did what either record says:
170
+ the platform's identifier is the platform's word, and the stub is
171
+ still the agent's side's word. That the platform keeps the identifier
172
+ at all: which one a platform writes into its log differs from one
173
+ platform to another, and is for whoever relies on it to find out. That
174
+ the fingerprint was made from the text the name says: a checker cannot
175
+ tell; only someone who holds that text can. An identifier that is
176
+ short or easy to guess gives no privacy through its fingerprint.
177
+ - *Against A1 and A3* (the agent's own side). The binding is written by
178
+ the agent's side, so a dishonest one can leave it out, or name a
179
+ wrong identifier; only the match with the platform's log, made later,
180
+ catches the second. It adds nothing against an agent that writes no
181
+ stub.
182
+ - *Two spellings of one address.* An HTTP address is taken exactly as it
183
+ was sent and never rewritten, so that two programs fingerprint the
184
+ same request the same way. A program that records a rewritten address
185
+ (`%2f` for `%2F`, a host in capitals) makes a fingerprint that will not
186
+ match: whoever writes the stub must give the address as sent.
187
+ - *A reserved name not on the list* is refused (`bad-field`), so that a
188
+ name that may be given a meaning later cannot be used now with another;
189
+ so is one of the four once-only names named twice (two `provared.arguments`
190
+ fingerprints in one stub would leave unclear which was the call's). A
191
+ book written before this rule that holds such a name no longer passes
192
+ its check.
193
+
126
194
  ## 4a. Limits, conditions, approvals and the other side's records
127
195
 
128
196
  **Protects.** That what the person allowed is stated exactly, and that a
@@ -235,6 +303,25 @@ disagree about. Totals are added as whole numbers of any size.
235
303
  of the arguments fixes what was asked for without holding it; where
236
304
  the arguments are few and easy to guess, the fingerprint can be
237
305
  guessed.
306
+ - **Documents named after the action** (`detailsAfter` in the stub
307
+ writer's `act`). The stub is first written and checked with the whole
308
+ book before the action, as always; after the action, it is signed
309
+ again with up to four further documents, still within the same call,
310
+ so that no other call comes between, and keeps the time the action
311
+ began. The room for them is kept beforehand: with today's limits the
312
+ largest stub, with 32 documents of the longest names, and a
313
+ countersignature still fits a line, and the writer checks this again
314
+ for each such call. If what `detailsAfter` gives cannot go in (it
315
+ fails, gives no answer within the time the other side is given to
316
+ countersign, gives more than four, or gives a document that would be
317
+ refused), the stub made before the action is written without them,
318
+ and the answer says why: an action that was taken always gets its
319
+ stub. What it gives is copied when it is read, so a later change to
320
+ it changes nothing. A call to the writer from inside it is refused at
321
+ once. It cannot be used with an approval, because an approval covers
322
+ exactly the documents the person saw. The stub is signed twice for
323
+ such an action, and only one of the two is written: a signer kept
324
+ elsewhere is asked once more.
238
325
  - **The check before acting refuses more in one case.** An action that
239
326
  would add to a period which a stub dated after it already overfills is
240
327
  refused, though a checker would report nothing new for it.
@@ -406,7 +493,8 @@ unnoticed).
406
493
  what is left still checks. This can hide the very stub that shows the agent outside its
407
494
  slip. A seal closes this for everything before it (section 6a). After
408
495
  the last seal, only a copy of a top fingerprint, with its number of
409
- entries, held by someone else would show it.
496
+ entries, or a copy of a later seal, held by someone else would show it
497
+ (section 6a, "Seals held elsewhere").
410
498
  - **Writing a different history with the agent's keys.** A1, A3 or A5
411
499
  can sign a second, different chain under the same slip. Countersigned
412
500
  stubs resist this, because the service's keys are needed. One-sided
@@ -476,8 +564,38 @@ person checking gives.
476
564
  - **The end of the book.** The last seal, with everything after it, can
477
565
  be removed, and what is left still checks. Only a copy of that seal, or
478
566
  of its top fingerprint and number of entries, held by someone else
479
- shows it. A public place where seals are kept would close this; it is
480
- not built.
567
+ shows it. A seal held elsewhere can be handed to the checker beside the
568
+ book (below), and a witness that signs for each seal (section 6f)
569
+ holds the latest one it signed for. A public place where seals are
570
+ kept, which gathers the seals of many books, is not built.
571
+ - **Seals held elsewhere.** The person, an auditor, or any copy kept out
572
+ of the recorder's reach can hand the checker, beside the book, up to 64
573
+ seal entries it holds (option `seals`, `--seal` on the command line, files on
574
+ the checking page). A seal at entry n stands at entry n of the
575
+ book, so the checker reports a book that ends before that place
576
+ (`book-cut-short`) and a book that holds another line there
577
+ (`seal-not-in-book`). This closes the end of a book cut off after a seal
578
+ someone else holds, back to any place before that seal, and a second
579
+ history shown to someone who holds a seal of the first. What it does
580
+ not close: a book cut back after the latest seal anyone holds; a book,
581
+ or a part of one, never shown to anyone who keeps a seal; and a holder
582
+ who keeps no seal at all. A seal handed over counts only where the
583
+ person named its recorder (`sealKeys`), and only where the device checked
584
+ its Ed25519 and ML-DSA-87 signatures; on a device without SLH-DSA (the
585
+ Python version, and browsers that have ML-DSA, such as Edge and Brave
586
+ 155 when tested) it counts on those two, and says so; on a device
587
+ without ML-DSA it is not used. It is compared with the book by its
588
+ content: the same content with other signatures is the same seal, and
589
+ is said, not reported against the book. It can only show a problem
590
+ with the book, never excuse one, so this widens nothing. Nothing in a
591
+ seal names its book, so a seal of another book by the same recorder
592
+ (one it kept before, when it started a new book) is reported against
593
+ the book being checked: hand over only that book's seals. A seal handed over that does not pass its own check is a
594
+ problem with the whole check, never set aside. Its time-stamps are
595
+ checked and shown, but are not used for the entries of the book: where
596
+ they differ from those beside the same seal in the book, the checker
597
+ says so. A Show does not use a seal held elsewhere, and says so: single
598
+ pages cannot show what the book holds at the place the seal states.
481
599
  - **Entries after the last time-stamp.** They are not time-stamped.
482
600
  - **A recorder who seals a false book.** A1 holding the agent's keys and
483
601
  the recorder's keys can write another history and seal it. A time-stamp
@@ -586,7 +704,17 @@ person checking gives.
586
704
  such a key, so the checker refuses the key itself. For the same reason
587
705
  it refuses an Ed25519 signature whose point R is of small order, under
588
706
  any key: the key's own holder could make one for any message, which one
589
- library accepts and another refuses. The key in a
707
+ library accepts and another refuses. It also refuses, itself, an
708
+ Ed25519 signature whose number S is not below the order L, which RFC
709
+ 8032 requires and some libraries do not check, and an ES256 passkey key
710
+ that is not a point on its curve (`bad-key`), which can check nothing
711
+ and which libraries report in different ways. A time-stamp signed with
712
+ Ed25519 must name SHA-512 as its fingerprint method, with no
713
+ parameters, as RFC 8419 requires, and may name the certificate that
714
+ signed it only once in each form (RFC 5035, sections 3 and 5): two
715
+ checkers could otherwise pick different certificates. A time-stamp is
716
+ read as strict DER throughout, every set it holds in the order DER
717
+ requires, so that two checkers cannot read one time-stamp in two ways. The key in a
590
718
  certificate must be written exactly as its standard sets out, so that
591
719
  two checkers cannot disagree about whether it can be read.
592
720
 
@@ -820,6 +948,174 @@ make a pass: it needs the keys of the agent that passes on.
820
948
  every stub under it, as outside the slip. The record is still sound.
821
949
  Only an eleventh pass in a row, which no slip can allow, is refused.
822
950
 
951
+ ## 6e. The denial
952
+
953
+ A denial (format description, section 28) is the agent's side's signed
954
+ statement that it did not take an action that was asked for, and who
955
+ said no: the check before acting, the person, or a rule of the software
956
+ around the agent.
957
+
958
+ **Protects.** That a denial in the book was signed by the agent the slip
959
+ names, or by the helper its pass names, under a slip that is earlier in
960
+ the book (`slip-missing`, `pass-missing`, `pass-mismatch`,
961
+ `signature-invalid`). A6 cannot make one. A7 cannot use one to change
962
+ any other answer: a denial is in no chain, adds to no total, and is never
963
+ counted against the agent, so a flood of denials, or a denial that names
964
+ an action far outside the slip, makes no stub read as outside it. A
965
+ denial changed after it was signed, or under another kind of record's
966
+ labels, is refused like any record. In this library, `act` writes a
967
+ denial only where it did not take the action, so one call through `act`,
968
+ `recordTools` or `record_function` leaves a stub or a denial, never both
969
+ (the connector for an agent's tools asks for no denial until it knows
970
+ the person will not approve). `deny` is different: it records whatever
971
+ its caller states, and a caller can write a denial for a request that
972
+ also has a stub; the checker shows both. The writer keeps to a set
973
+ number of denials an hour of its own clock (600 by default), counting
974
+ each it writes at the clock's time, so that an agent that asks again and
975
+ again cannot fill its book quickly: at 600 an hour a book's 100,000
976
+ entries still fill in about a week. A stub is never kept out by that
977
+ limit.
978
+
979
+ **Does not protect.**
980
+
981
+ - **It is the agent's side's own word.** A3 can write a denial for an
982
+ action it then took some other way, or a false reason. Only the other
983
+ side's records, or the service's own refusal, can show otherwise.
984
+ - **An agent can simply not write one.** A book with no denial shows
985
+ nothing about how often the agent was stopped. A1 or A2 can also leave
986
+ denials out of a copy of the book after the last seal, as any entry.
987
+ - **What was asked for is in clear.** A denial names the action, the
988
+ amount and the service. Its documents are fingerprints only, and the
989
+ library never writes arguments into it; but a fingerprint of a short
990
+ or guessable value can be guessed.
991
+ - **The source is not checked.** Nothing shows that the person, or a
992
+ rule, said no: `person` and `rule` are the agent's side's statement.
993
+ A denial by the check before acting names the codes the check gave,
994
+ and nothing in the record shows that the check was made.
995
+ - **Older checkers** refuse a book that holds a denial (`unknown-entry`).
996
+
997
+ ## 6f. Witnesses, and a book shown two ways
998
+
999
+ A recorder that keeps a book (A1, A2) can show one history to one reader
1000
+ and another to another (a "split view"): each copy checks, and each is
1001
+ sealed, so a reader who holds one copy cannot see the other. A witness
1002
+ (format description, section 29) is a party with a key set of its own
1003
+ that keeps, for each recorder, person and agent, the latest seal it
1004
+ signed for, and signs a statement for a new seal only where the new seal
1005
+ extends that one: in the same book, by a consistency proof (RFC 9162,
1006
+ section 2.1.4), or as the first seal of the next book (section 21.6). The
1007
+ person and the agent are those the permission on a book's first line
1008
+ names: its passkey and the agent's key set. So every permission one
1009
+ person gives one agent under one recorder, renewals included, is one
1010
+ sequence: the independent review showed that a sequence known by the
1011
+ permission alone let a book that started with a renewal fork the
1012
+ history, and a witness now refuses it. The statement sits beside the seal on its line, or is
1013
+ handed to a checker later with a copy of the seal.
1014
+
1015
+ **Protects.** That a statement a checker counts was signed by a witness
1016
+ the person named, by the fingerprint of its key set, and speaks of that
1017
+ very seal: its `seal`, `size` and `root` must be the seal's, both its
1018
+ signatures must check, and it may not be dated more than 300 seconds
1019
+ before the seal (`witness-invalid`). A6 and A7 cannot make one, and a
1020
+ statement from a witness nobody named is shown and not counted. A
1021
+ statement that does not pass is a problem; one handed over beside the
1022
+ book is a problem with the whole check, and the seal it came with is
1023
+ used all the same. Being witnessed excuses nothing: it changes no other
1024
+ answer, and a book with a problem is never said to be witnessed.
1025
+
1026
+ A witness knows which books are one sequence only by the passkey and the
1027
+ agent of the permission on their first line and the keys of their
1028
+ recorder, and the recorder (A1, A2) chooses the first line and its keys: it can start a history with another first line, or
1029
+ seal it with new keys, and the same honest witness signs for it as
1030
+ another sequence. So a statement counts only where the person fixed
1031
+ both: the book's first line is a permission that passed its check,
1032
+ signed by a passkey the person named (`issuerKeys`), and the person
1033
+ named the recorders they expect (`sealKeys`). The independent review of
1034
+ this step showed a history that began with made-up terms, then the
1035
+ permission, signed by the same witness and read as witnessed; it now
1036
+ reads as not witnessed, and the witness itself no longer keeps a book
1037
+ whose first line is not a permission.
1038
+
1039
+ And every permission among the entries a seal covers must name the same
1040
+ passkey and agent as the first line's. The third round of the review
1041
+ showed a fork through a second agent of the same person under the same
1042
+ recorder, the gateway's own set-up: a book that started with agent Y's
1043
+ permission, then held agent X's permission and X's stubs without the
1044
+ one over its limit, was signed by the witness as the first book of the
1045
+ person and agent Y, and read as witnessed. It now reads as not
1046
+ witnessed, with a note saying why; so does one that starts with a
1047
+ second passkey's permission for X. A witness cannot refuse such a book
1048
+ itself: it sees a book's first line, not its entries. A Show counts a
1049
+ statement only where its pages hold every entry the seal covers, so it
1050
+ never counts one that the whole book would not.
1051
+
1052
+ What it narrows, where the witness keeps section 29.3 and the person
1053
+ fixed the start: a second history sealed by the same recorder and
1054
+ starting from any permission that passkey gave the same agent needs that
1055
+ witness to sign for it too, which it does not do. So two readers who name that witness, the
1056
+ same passkey and the same recorder cannot be shown two such histories
1057
+ that both carry its statements and that disagree before the earlier of
1058
+ the two seals it signed for. A new book cannot start from an earlier
1059
+ seal than the latest the witness holds, so the books of one permission
1060
+ cannot fork either. Two witnesses need two to fail. The latest seal a
1061
+ witness holds, handed over beside the book it is of as a seal held
1062
+ elsewhere (section 6a), shows that book cut back to before that seal
1063
+ (`book-cut-short`, `seal-not-in-book`). The witness program in the
1064
+ library (`openWitness`) checks a seal's three signatures, signs nothing
1065
+ on a device that cannot check SLH-DSA (so there is none in the Python
1066
+ version), ties the first line to the seal with an audit path at first
1067
+ contact and at each new book, keeps it tied with each consistency proof,
1068
+ never signs two different seals of one book at one size, never again
1069
+ signs for a book once it has signed for the next, and hands back what it
1070
+ holds with each statement, to be kept before the statement is given
1071
+ out.
1072
+
1073
+ **Does not protect.**
1074
+
1075
+ - **Other recorder keys, or another agent.** A history sealed with
1076
+ another key set, even one the person also named, or that starts from a
1077
+ permission for another agent, is another sequence to a witness, and a
1078
+ fork made that way is not caught. A person who names two recorders
1079
+ should know that a fork sealed with the second reads as witnessed. One
1080
+ recorder key set keeps one sequence for each person and agent, so books
1081
+ kept side by side for one agent need recorder keys of their own, and
1082
+ are then other sequences.
1083
+ - **What a later book holds.** A later book can repeat, or leave out,
1084
+ what an earlier book holds: each book is checked on its own.
1085
+ - **A book sealed again under another number.** A book cut short can be
1086
+ sealed again with another book number. A seal held elsewhere is then of
1087
+ another number than the book, is not compared with it, and gives no
1088
+ pass: the command-line checker says "Seals held elsewhere compared?
1089
+ NO" and does not end with code 0, and the checking page gives no green
1090
+ answer. The reader learns that their seal was not compared, not where
1091
+ the book was cut.
1092
+ - **What is never shown to a witness.** A recorder can keep a book, or
1093
+ the end of one, from every witness. Nothing in a book obliges it to be
1094
+ witnessed, and a checker that is not handed the witness's latest seal
1095
+ does not know of later seals. Where that latest seal is of a later
1096
+ book, a checker of an earlier book cannot use it to show that earlier
1097
+ book cut short: it cannot tell whether a seal of the next book is that
1098
+ book's first (section 21.6).
1099
+ - **A witness that fails.** A witness that signs for two histories, or
1100
+ that loses what it holds or is put back to an older copy of it, can
1101
+ sign a fork, and nothing in either history shows it. The library's
1102
+ witness, opened again from what it kept, signs nothing until it is
1103
+ brought up to date (`update`) and told so (`ready`); it cannot tell
1104
+ whether what it was given is the latest it gave out. Whoever can change
1105
+ what it keeps can make it forget a sequence, which it then signs for
1106
+ again from any seal: its state must be kept as safely as its keys.
1107
+ - **The entries.** A witness sees a seal's size and top fingerprint,
1108
+ not the entries: it shows that the entries existed in that form when
1109
+ it saw the seal, not that they are true.
1110
+ - **Time.** A statement's `when` is the witness's own word, and is not
1111
+ used as a time-stamp.
1112
+ - **Limits across books.** A checker counts a limit within the book it
1113
+ checks, not across the books of a permission.
1114
+ - **A device that cannot check both of a statement's signatures**
1115
+ counts nothing, and the record is not fully checked there.
1116
+ - **Older checkers** refuse a seal's line that holds `witnesses`
1117
+ (`unknown-entry`), and a seal that gives `book` (`bad-field`).
1118
+
823
1119
  ## 7. The checker and the checking page
824
1120
 
825
1121
  **Protects.** A7 cannot crash the checker, make it run a script, or make
@@ -850,7 +1146,11 @@ it show a pass for a record that does not check.
850
1146
  the checker itself put there.
851
1147
  - "Within its slip" is said only if every stub and every pass was
852
1148
  compared on this device.
853
- - Records over a fixed size, or nested too deeply, are refused.
1149
+ - Records over a fixed size, or nested too deeply, are refused. A book
1150
+ may hold 100,000 lines of 131,072 bytes, about 13 gigabytes in all;
1151
+ this library takes a book as one text, so it can check no book larger
1152
+ than one text the device can hold, and a checker should bound the size
1153
+ it accepts (format description, section 9).
854
1154
  - The content of a record must be written in one canonical form (RFC
855
1155
  8785). A record with a repeated field name, stray spaces or an unusual
856
1156
  number form is refused, so two checkers cannot read the same record in
@@ -915,7 +1215,10 @@ it show a pass for a record that does not check.
915
1215
  ## 8. What is refused, and the test that proves it
916
1216
 
917
1217
  Each row is one test in `test/refusals.test.mjs`, named by its code. A
918
- further test reads this table and fails if a code here has no test.
1218
+ further test reads this table and fails if a code here has no test. This
1219
+ table is also the format's own list of finding codes, from which a denial
1220
+ names its reasons (format description, section 28); `test/denial.test.mjs`
1221
+ fails if the two differ.
919
1222
 
920
1223
  | Code | What is refused or reported |
921
1224
  |---|---|
@@ -928,8 +1231,8 @@ further test reads this table and fails if a code here has no test.
928
1231
  | `payload-not-canonical` | Content that is not in the canonical form, including a repeated field name |
929
1232
  | `payload-type-mismatch` | Content of one kind under the label of another, for example a stub presented as a countersignature |
930
1233
  | `bad-field` | A missing, extra or wrongly typed field |
931
- | `bad-key` | A public key that is not exactly of an accepted kind |
932
- | `signature-invalid` | A signature that does not fit the key |
1234
+ | `bad-key` | A public key that is not exactly of an accepted kind, an Ed25519 key of small order or written in more than one way, or an ES256 key that is not a point on its curve |
1235
+ | `signature-invalid` | A signature that does not fit the key, or an Ed25519 signature whose R is a point of small order or whose S is not below the order L |
933
1236
  | `passkey-wrong-type` | A passkey answer that was made for creating a passkey, not for signing |
934
1237
  | `passkey-challenge-mismatch` | A passkey signature made for other content |
935
1238
  | `passkey-origin-mismatch` | A passkey used on a website other than the one the slip names |
@@ -968,10 +1271,13 @@ further test reads this table and fails if a code here has no test.
968
1271
  | `seal-mismatch` | A seal that does not fit the entries before it: an entry was changed, added or removed after the seal was made. In a Show: a seal for another book, or for another length of this one |
969
1272
  | `seal-chain-broken` | A seal that does not name the seal before it: a seal is missing, moved or changed |
970
1273
  | `sealer-not-expected` | A seal signed with keys other than the ones the checker was told to expect |
1274
+ | `book-cut-short` | A book that ends before the place of a seal held elsewhere and handed over beside it: its end was cut off after that seal was made |
1275
+ | `seal-not-in-book` | A book that holds another line at the place of a seal held elsewhere and handed over beside it: it was changed after that seal was made, or the seal is of another book |
1276
+ | `witness-invalid` | A witness statement, beside a seal in the book or handed over with a seal held elsewhere, whose signatures do not fit the keys it gives, that speaks of another seal, or that is dated more than 300 seconds before its seal |
971
1277
  | `dated-after-stamp` | An entry dated later than the outside time-stamp that covers it, or a seal dated later than its own time-stamp |
972
1278
  | `stamp-bad-data` | A time-stamp that is not laid out as its standard sets out |
973
1279
  | `stamp-wrong-data` | A time-stamp made for something other than this seal |
974
- | `stamp-invalid` | A time-stamp whose signature does not check, or that is dated outside the time its service's certificate was in force |
1280
+ | `stamp-invalid` | A time-stamp whose signature does not check, that names the certificate that signed it twice in one form, that is signed with Ed25519 and names a fingerprint method other than SHA-512, or that is dated outside the time its service's certificate was in force |
975
1281
  | `headers-invalid` | A chain of block headers in which a header breaks a rule that every Bitcoin node applies, that does not hold the known blocks at their places, or that ends before the last of them (tested in `test/headers.test.mjs`) |
976
1282
  | `record-not-sound` | The check before acting: the record so far has a problem, or could not be checked on this device, so no action is allowed |
977
1283
  | `proof-invalid` | A one-page proof that does not lead to the top fingerprint |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "provared",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "Proof of what an AI agent was allowed to do, and what it then did. A passkey-signed permission with limits a machine can check, a signed receipt for each action, and a free checker. Evidence, not a verdict.",
5
5
  "author": "Pavel Izmaylov",
6
6
  "license": "Apache-2.0 AND CC-BY-4.0",
@@ -71,7 +71,7 @@
71
71
  "node": ">=24.7"
72
72
  },
73
73
  "scripts": {
74
- "test": "node --disable-warning=ExperimentalWarning --test",
74
+ "test": "node --disable-warning=ExperimentalWarning --test \"test/**/*.test.mjs\"",
75
75
  "check": "node --disable-warning=ExperimentalWarning bin/provared-check.mjs",
76
76
  "headers": "node bin/provared-headers.mjs",
77
77
  "demo": "node --disable-warning=ExperimentalWarning demo/server.mjs"
@@ -6,7 +6,7 @@
6
6
  // request at all.
7
7
 
8
8
  import { checkBook, checkShow } from '../src/check.js';
9
- import { readBlocks, readFingerprints, renderResult, shown } from './render.js';
9
+ import { readBlocks, readFingerprints, readHanded, renderResult, shown } from './render.js';
10
10
 
11
11
  const status = document.getElementById('status');
12
12
  const result = document.getElementById('result');
@@ -14,9 +14,6 @@ const result = document.getElementById('result');
14
14
  // This page reads the whole file into memory. A larger book is checked
15
15
  // with the command-line checker.
16
16
  const MAX_FILE_BYTES = 200000000;
17
- // A copy of a cancellation, or a file of disclosures, is small.
18
- const MAX_HANDED_BYTES = 1000000;
19
- const MAX_COPIES = 16;
20
17
 
21
18
  // What the person already trusts: one fingerprint to a line. A line that
22
19
  // is not a fingerprint stops the check, and the person is told which box.
@@ -25,6 +22,7 @@ const BOXES = [
25
22
  ['trust-sealer', 'sealKeys', 'whoever keeps and seals the book'],
26
23
  ['trust-stamps', 'stampServices', 'time-stamp services'],
27
24
  ['trust-vouchers', 'vouchers', 'organisations whose vouching you trust'],
25
+ ['trust-witnesses', 'witnesses', 'witnesses you trust'],
28
26
  ];
29
27
 
30
28
  function trusted() {
@@ -42,34 +40,14 @@ function trusted() {
42
40
  return options;
43
41
  }
44
42
 
45
- async function jsonFrom(file, what) {
46
- if (file.size > MAX_HANDED_BYTES) throw new Error(`The file of ${what}, ${shown(file.name)}, is too large. Nothing was checked.`);
47
- try {
48
- return JSON.parse(await file.text());
49
- } catch {
50
- throw new Error(`The file of ${what}, ${shown(file.name)}, is not JSON. Nothing was checked. Choose another file, or clear these files.`);
51
- }
52
- }
53
-
54
- // What the person was handed with the record: their own copies of
55
- // cancellations, and disclosures for covered fields. A file that cannot be
56
- // read stops the check: it is never set aside silently.
57
- async function handedOver() {
58
- const options = {};
59
- const said = [];
60
- const copies = [...document.getElementById('cancellations').files];
61
- if (copies.length > MAX_COPIES) throw new Error('At most 16 copies of cancellations can be handed over at once. Nothing was checked.');
62
- if (copies.length) {
63
- options.cancellations = [];
64
- for (const file of copies) options.cancellations.push(await jsonFrom(file, 'a cancellation'));
65
- said.push(copies.length === 1 ? 'one copy of a cancellation' : `${copies.length} copies of cancellations`);
66
- }
67
- const [disclosures] = document.getElementById('disclosures').files;
68
- if (disclosures) {
69
- options.disclosures = await jsonFrom(disclosures, 'disclosures');
70
- said.push('disclosures for covered fields');
71
- }
72
- return { options, said };
43
+ // What the person was handed with the record: the files chosen in the
44
+ // panel "What you were handed with the record" (render.js, readHanded).
45
+ function handedOver() {
46
+ return readHanded({
47
+ cancellations: [...document.getElementById('cancellations').files],
48
+ seals: [...document.getElementById('seals').files],
49
+ disclosures: document.getElementById('disclosures').files[0] ?? null,
50
+ });
73
51
  }
74
52
 
75
53
  async function check(text, name, { beside = true, trust = null } = {}) {
@@ -131,6 +109,7 @@ if (chooser.files.length > 0) checkChosen(chooser);
131
109
 
132
110
  document.getElementById('clear-beside').addEventListener('click', () => {
133
111
  document.getElementById('cancellations').value = '';
112
+ document.getElementById('seals').value = '';
134
113
  document.getElementById('disclosures').value = '';
135
114
  status.textContent = 'The files you were handed with a record are cleared.';
136
115
  });
package/page/index.html CHANGED
@@ -26,6 +26,8 @@
26
26
  <textarea id="trust-stamps" rows="2" spellcheck="false"></textarea>
27
27
  <label for="trust-vouchers">Organisations whose vouching for names you trust (the fingerprint of each one's key set)</label>
28
28
  <textarea id="trust-vouchers" rows="2" spellcheck="false"></textarea>
29
+ <label for="trust-witnesses">Witnesses you trust to have seen the seals (the fingerprint of each one's key set)</label>
30
+ <textarea id="trust-witnesses" rows="2" spellcheck="false"></textarea>
29
31
  <label for="trust-blocks">Blocks of a public blockchain that you trust to be part of the chain (the fingerprint of each block: 64 characters, the digits 0 to 9 and the letters a to f)</label>
30
32
  <textarea id="trust-blocks" rows="2" spellcheck="false"></textarea>
31
33
  </details>
@@ -34,6 +36,8 @@
34
36
  <p class="quiet">Choose these files first, then choose the record file. They stay chosen, and are used with every record you check, until you clear them. The sample record is checked without them.</p>
35
37
  <label for="cancellations">The person's own copies of cancellations: one file for each, up to 16. A copy counts even where the book leaves the cancellation out. A file may also hold what the agent's side signed when it was handed the cancellation.</label>
36
38
  <input type="file" id="cancellations" accept=".json,.txt" multiple>
39
+ <label for="seals">Seals of the book held elsewhere, by you, an auditor or a copy kept apart: one file for each, up to 64. The book must hold each at the place it states; one that ends before it was cut short. A seal counts only where you named its recorder above. A file may also hold statements that witnesses signed for the seal.</label>
40
+ <input type="file" id="seals" accept=".json,.txt" multiple>
37
41
  <label for="disclosures">Disclosures for covered fields of a slip: one file</label>
38
42
  <input type="file" id="disclosures" accept=".json,.txt">
39
43
  <p><button type="button" class="second" id="clear-beside">Clear these files</button></p>