provared 0.5.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
 
@@ -479,7 +493,8 @@ unnoticed).
479
493
  what is left still checks. This can hide the very stub that shows the agent outside its
480
494
  slip. A seal closes this for everything before it (section 6a). After
481
495
  the last seal, only a copy of a top fingerprint, with its number of
482
- 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").
483
498
  - **Writing a different history with the agent's keys.** A1, A3 or A5
484
499
  can sign a second, different chain under the same slip. Countersigned
485
500
  stubs resist this, because the service's keys are needed. One-sided
@@ -549,8 +564,38 @@ person checking gives.
549
564
  - **The end of the book.** The last seal, with everything after it, can
550
565
  be removed, and what is left still checks. Only a copy of that seal, or
551
566
  of its top fingerprint and number of entries, held by someone else
552
- shows it. A public place where seals are kept would close this; it is
553
- 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.
554
599
  - **Entries after the last time-stamp.** They are not time-stamped.
555
600
  - **A recorder who seals a false book.** A1 holding the agent's keys and
556
601
  the recorder's keys can write another history and seal it. A time-stamp
@@ -659,7 +704,17 @@ person checking gives.
659
704
  such a key, so the checker refuses the key itself. For the same reason
660
705
  it refuses an Ed25519 signature whose point R is of small order, under
661
706
  any key: the key's own holder could make one for any message, which one
662
- 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
663
718
  certificate must be written exactly as its standard sets out, so that
664
719
  two checkers cannot disagree about whether it can be read.
665
720
 
@@ -893,6 +948,174 @@ make a pass: it needs the keys of the agent that passes on.
893
948
  every stub under it, as outside the slip. The record is still sound.
894
949
  Only an eleventh pass in a row, which no slip can allow, is refused.
895
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
+
896
1119
  ## 7. The checker and the checking page
897
1120
 
898
1121
  **Protects.** A7 cannot crash the checker, make it run a script, or make
@@ -923,7 +1146,11 @@ it show a pass for a record that does not check.
923
1146
  the checker itself put there.
924
1147
  - "Within its slip" is said only if every stub and every pass was
925
1148
  compared on this device.
926
- - 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).
927
1154
  - The content of a record must be written in one canonical form (RFC
928
1155
  8785). A record with a repeated field name, stray spaces or an unusual
929
1156
  number form is refused, so two checkers cannot read the same record in
@@ -988,7 +1215,10 @@ it show a pass for a record that does not check.
988
1215
  ## 8. What is refused, and the test that proves it
989
1216
 
990
1217
  Each row is one test in `test/refusals.test.mjs`, named by its code. A
991
- 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.
992
1222
 
993
1223
  | Code | What is refused or reported |
994
1224
  |---|---|
@@ -1001,8 +1231,8 @@ further test reads this table and fails if a code here has no test.
1001
1231
  | `payload-not-canonical` | Content that is not in the canonical form, including a repeated field name |
1002
1232
  | `payload-type-mismatch` | Content of one kind under the label of another, for example a stub presented as a countersignature |
1003
1233
  | `bad-field` | A missing, extra or wrongly typed field |
1004
- | `bad-key` | A public key that is not exactly of an accepted kind |
1005
- | `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 |
1006
1236
  | `passkey-wrong-type` | A passkey answer that was made for creating a passkey, not for signing |
1007
1237
  | `passkey-challenge-mismatch` | A passkey signature made for other content |
1008
1238
  | `passkey-origin-mismatch` | A passkey used on a website other than the one the slip names |
@@ -1041,10 +1271,13 @@ further test reads this table and fails if a code here has no test.
1041
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 |
1042
1272
  | `seal-chain-broken` | A seal that does not name the seal before it: a seal is missing, moved or changed |
1043
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 |
1044
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 |
1045
1278
  | `stamp-bad-data` | A time-stamp that is not laid out as its standard sets out |
1046
1279
  | `stamp-wrong-data` | A time-stamp made for something other than this seal |
1047
- | `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 |
1048
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`) |
1049
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 |
1050
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.5.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>