@sanning/proof 0.19.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -29
- package/dist/agent-record.d.ts +62 -0
- package/dist/agent-record.js +527 -0
- package/dist/agent-schemas.generated.d.ts +15 -0
- package/dist/agent-schemas.generated.js +5759 -0
- package/dist/case-file.d.ts +32 -89
- package/dist/case-file.js +41 -93
- package/dist/case.d.ts +343 -810
- package/dist/case.js +693 -1151
- package/dist/chain.d.ts +19 -47
- package/dist/chain.js +78 -205
- package/dist/claims.d.ts +211 -0
- package/dist/claims.js +1081 -0
- package/dist/cli.d.ts +45 -68
- package/dist/cli.js +618 -1022
- package/dist/compose.js +23 -65
- package/dist/crypto.d.ts +7 -8
- package/dist/crypto.js +60 -147
- package/dist/declaration.d.ts +68 -194
- package/dist/declaration.js +175 -518
- package/dist/environment.d.ts +9 -30
- package/dist/environment.js +17 -66
- package/dist/evidence.d.ts +119 -160
- package/dist/evidence.js +744 -1103
- package/dist/exit-codes.d.ts +11 -27
- package/dist/exit-codes.js +24 -59
- package/dist/file-match.d.ts +33 -79
- package/dist/file-match.js +33 -69
- package/dist/grading.d.ts +98 -135
- package/dist/grading.js +224 -380
- package/dist/handoff.d.ts +62 -160
- package/dist/handoff.js +153 -393
- package/dist/index.d.ts +14 -10
- package/dist/index.js +60 -167
- package/dist/json-schema.d.ts +29 -0
- package/dist/json-schema.js +298 -0
- package/dist/merkle.js +16 -28
- package/dist/message-parts.d.ts +56 -212
- package/dist/message-parts.js +142 -502
- package/dist/side-content.d.ts +11 -22
- package/dist/side-content.js +22 -65
- package/dist/types.d.ts +17 -0
- package/dist/types.js +19 -5
- package/dist/verifier.d.ts +40 -114
- package/dist/verifier.js +196 -535
- package/dist/witness-cache.d.ts +24 -45
- package/dist/witness-cache.js +38 -81
- package/dist/witness-lookup.d.ts +36 -57
- package/dist/witness-lookup.js +89 -139
- package/dist/zip-reader.d.ts +18 -33
- package/dist/zip-reader.js +19 -34
- package/package.json +11 -3
- package/src/agent-record.ts +608 -0
- package/src/agent-schemas.generated.ts +5764 -0
- package/src/case-file.ts +45 -109
- package/src/case.ts +848 -1322
- package/src/chain.ts +85 -224
- package/src/claims.ts +1253 -0
- package/src/cli.ts +714 -1176
- package/src/compose.ts +33 -79
- package/src/crypto.ts +60 -147
- package/src/declaration.ts +219 -656
- package/src/environment.ts +17 -65
- package/src/evidence.ts +958 -1381
- package/src/exit-codes.ts +24 -63
- package/src/file-match.ts +40 -89
- package/src/grading.ts +287 -421
- package/src/handoff.ts +175 -427
- package/src/index.ts +132 -177
- package/src/json-schema.ts +295 -0
- package/src/merkle.ts +16 -28
- package/src/message-parts.ts +155 -533
- package/src/side-content.ts +25 -68
- package/src/types.ts +55 -36
- package/src/verifier.ts +202 -526
- package/src/witness-cache.ts +45 -94
- package/src/witness-lookup.ts +107 -177
- package/src/zip-reader.ts +20 -38
- package/vectors/README.md +52 -34
- package/vectors/agent-record.json +2175 -0
- package/vectors/case-file-index.json +1 -1
- package/vectors/case-split.json +2 -2
- package/vectors/chain-reading.json +3 -3
- package/vectors/file-match.json +285 -148
- package/vectors/jcs-reader.json +6 -6
- package/vectors/pack-grading.json +102 -25
- package/vectors/sandbox-evidence.json +597 -580
- package/vectors/stamp-on-chain.json +18 -18
- package/vectors/witness-cache.json +49 -49
- package/dist/agent-proof.d.ts +0 -28
- package/dist/agent-proof.js +0 -226
- package/dist/run-adapters.d.ts +0 -10
- package/dist/run-adapters.js +0 -35
- package/dist/run.d.ts +0 -209
- package/dist/run.js +0 -1405
- package/src/agent-proof.ts +0 -264
- package/src/run-adapters.ts +0 -44
- package/src/run.ts +0 -1598
package/dist/witness-lookup.js
CHANGED
|
@@ -1,24 +1,11 @@
|
|
|
1
1
|
// The public-record (witness) lookup the CLI runs with `--gateways`
|
|
2
|
-
// (evidence-bundle.md §5.5.6
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// a browser app, call the SAME implementation rather than each keeping its
|
|
6
|
-
// own copy that can drift.
|
|
2
|
+
// (evidence-bundle.md §5.5.6): re-fetch each pack's witness on the public record
|
|
3
|
+
// and report what it said. The CLI and non-CLI callers (the verify page, a
|
|
4
|
+
// browser app) share this one implementation.
|
|
7
5
|
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
// caller supplies one (a browser page's own `fetch`, or a test's fake), that
|
|
12
|
-
// is the ONE this module calls; where none is given, it falls back to the
|
|
13
|
-
// ambient global `fetch`, the same fallback `cli.ts` already applied at its
|
|
14
|
-
// own call site before this module existed.
|
|
15
|
-
//
|
|
16
|
-
// `onChainHalf` and `witnessLine` are the CLI's own building blocks,
|
|
17
|
-
// UNCHANGED (proof#200 is additive: the CLI's `case` output and exit codes are
|
|
18
|
-
// byte-for-byte what they were). `lookupPublicRecord` is the new export:
|
|
19
|
-
// one pack (or several) in, one four-state result out, with a pack's
|
|
20
|
-
// `witness-cache.json` read as part of the pack rather than as a side file a
|
|
21
|
-
// caller must remember to also pass in.
|
|
6
|
+
// The network call is the one exception to the kernel's purity (specs/architecture.md §3).
|
|
7
|
+
// It never runs unless a caller hands in a gateway, and `options.fetchImpl`
|
|
8
|
+
// is the seam: the caller's `fetch` if given, else the ambient global.
|
|
22
9
|
import { SIMULATED_WITNESS_KIND, verifyEvidenceBundle } from "./evidence.js";
|
|
23
10
|
import { WITNESS_NOT_LOOKED_UP, renderWitnessLine } from "./case.js";
|
|
24
11
|
import { checkWitnessCache, readWitnessCache, renderWitnessTime, } from "./witness-cache.js";
|
|
@@ -35,23 +22,60 @@ function witnessTimeRow(t) {
|
|
|
35
22
|
})),
|
|
36
23
|
};
|
|
37
24
|
}
|
|
25
|
+
/** One pack's witnesses as a lookup left them: how many, and each one's rollup. */
|
|
26
|
+
export function onChainRow(ref, result) {
|
|
27
|
+
const witnesses = [...result.checkpoints, ...(result.stamps ?? [])];
|
|
28
|
+
const row = {
|
|
29
|
+
ref,
|
|
30
|
+
witnesses: witnesses.length,
|
|
31
|
+
confirmed: 0,
|
|
32
|
+
mismatched: 0,
|
|
33
|
+
unreachable: 0,
|
|
34
|
+
not_checked: 0,
|
|
35
|
+
};
|
|
36
|
+
for (const w of witnesses) {
|
|
37
|
+
const rollup = w.onChain?.rollup ?? null;
|
|
38
|
+
if (rollup === "confirm")
|
|
39
|
+
row.confirmed++;
|
|
40
|
+
else if (rollup === "mismatch")
|
|
41
|
+
row.mismatched++;
|
|
42
|
+
else if (rollup === "unreachable")
|
|
43
|
+
row.unreachable++;
|
|
44
|
+
else
|
|
45
|
+
row.not_checked++;
|
|
46
|
+
}
|
|
47
|
+
const simulated = witnesses.filter((w) => w.anchorRef?.kind === SIMULATED_WITNESS_KIND).length;
|
|
48
|
+
if (simulated > 0)
|
|
49
|
+
row.simulated = simulated;
|
|
50
|
+
const answered = new Set();
|
|
51
|
+
for (const w of witnesses) {
|
|
52
|
+
for (const outcome of w.onChain?.perGateway ?? []) {
|
|
53
|
+
if (outcome.outcome === "confirm" || outcome.outcome === "mismatch") {
|
|
54
|
+
answered.add(outcome.gateway);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return { row, answered };
|
|
59
|
+
}
|
|
38
60
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* does the verify page's case reading, so the case verdict stays the one both
|
|
42
|
-
* surfaces compute. This adds the half the reading names as not checked.
|
|
43
|
-
*
|
|
44
|
-
* Moved from `cli.ts` unchanged, apart from taking `fetchImpl` directly
|
|
45
|
-
* instead of a `Cli` stream (`io.fetchImpl ?? fetch`, the same fallback the
|
|
46
|
-
* CLI already applied at its own call site).
|
|
61
|
+
* `differs` where a lookup found other bytes or another time, `not_settled` where one
|
|
62
|
+
* did not settle, `confirmed` otherwise. Only `differs` moves a verdict.
|
|
47
63
|
*/
|
|
48
|
-
export
|
|
64
|
+
export function onChainOutcome(rows) {
|
|
65
|
+
if (rows.some((r) => r.mismatched > 0 || (r.witness_times ?? []).some((t) => t.outcome === "differs"))) {
|
|
66
|
+
return "differs";
|
|
67
|
+
}
|
|
68
|
+
if (rows.some((r) => r.witnesses === 0 || r.unreachable > 0 || r.not_checked > 0)) {
|
|
69
|
+
return "not_settled";
|
|
70
|
+
}
|
|
71
|
+
return "confirmed";
|
|
72
|
+
}
|
|
49
73
|
/**
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
74
|
+
* Each pack's witnesses, re-fetched through `verifyEvidenceBundle`. Outside the
|
|
75
|
+
* case reading on purpose: `readCase` makes no network call, so the case verdict
|
|
76
|
+
* is the same on every surface. This adds the half the reading names as not checked.
|
|
53
77
|
*/
|
|
54
|
-
|
|
78
|
+
export async function onChainHalf(packs, gateways, options = {}) {
|
|
55
79
|
if (gateways.length === 0)
|
|
56
80
|
return { checked: false, gateways: [], packs: [], verdict: "not_checked" };
|
|
57
81
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
@@ -59,44 +83,14 @@ witnessed) {
|
|
|
59
83
|
const answered = new Set();
|
|
60
84
|
for (const [ref, bundle, cached] of packs) {
|
|
61
85
|
const result = await verifyEvidenceBundle(bundle, { gateways: [...gateways], fetchImpl });
|
|
62
|
-
const
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
confirmed: 0,
|
|
67
|
-
mismatched: 0,
|
|
68
|
-
unreachable: 0,
|
|
69
|
-
not_checked: 0,
|
|
70
|
-
};
|
|
71
|
-
witnessed?.push((result.stamps ?? []).filter((st) => st.ok && st.onChain?.rollup === "confirm").map((st) => st.stampRef));
|
|
72
|
-
for (const w of witnesses) {
|
|
73
|
-
const rollup = w.onChain?.rollup ?? null;
|
|
74
|
-
if (rollup === "confirm")
|
|
75
|
-
row.confirmed++;
|
|
76
|
-
else if (rollup === "mismatch")
|
|
77
|
-
row.mismatched++;
|
|
78
|
-
else if (rollup === "unreachable")
|
|
79
|
-
row.unreachable++;
|
|
80
|
-
else
|
|
81
|
-
row.not_checked++;
|
|
82
|
-
}
|
|
83
|
-
const simulated = witnesses.filter((w) => w.anchorRef?.kind === SIMULATED_WITNESS_KIND).length;
|
|
84
|
-
if (simulated > 0)
|
|
85
|
-
row.simulated = simulated;
|
|
86
|
-
// The witness times the pack's witness-cache.json gives, looked up where
|
|
87
|
-
// it gives any (5.6.6, v1.25, A30). A pack with no cache gets no key and
|
|
88
|
-
// no request.
|
|
86
|
+
const { row, answered: heard } = onChainRow(ref, result);
|
|
87
|
+
for (const g of heard)
|
|
88
|
+
answered.add(g);
|
|
89
|
+
// The witness times the pack's witness-cache.json gives (5.6.6). A pack with no cache gets no key and no request.
|
|
89
90
|
const times = await checkWitnessCache(cached, gateways, fetchImpl);
|
|
90
91
|
if (times.length > 0)
|
|
91
92
|
row.witness_times = times.map(witnessTimeRow);
|
|
92
93
|
rows.push(row);
|
|
93
|
-
for (const w of witnesses) {
|
|
94
|
-
for (const outcome of w.onChain?.perGateway ?? []) {
|
|
95
|
-
if (outcome.outcome === "confirm" || outcome.outcome === "mismatch") {
|
|
96
|
-
answered.add(outcome.gateway);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
94
|
for (const t of times) {
|
|
101
95
|
for (const a of t.answers) {
|
|
102
96
|
if (a.outcome === "matches" || a.outcome === "differs")
|
|
@@ -104,11 +98,7 @@ witnessed) {
|
|
|
104
98
|
}
|
|
105
99
|
}
|
|
106
100
|
}
|
|
107
|
-
const verdict = rows
|
|
108
|
-
? "failed"
|
|
109
|
-
: rows.some((r) => r.witnesses === 0 || r.unreachable > 0 || r.not_checked > 0)
|
|
110
|
-
? "undetermined"
|
|
111
|
-
: "confirmed";
|
|
101
|
+
const verdict = onChainOutcome(rows);
|
|
112
102
|
return {
|
|
113
103
|
answered: gateways.filter((g) => answered.has(g)),
|
|
114
104
|
checked: true,
|
|
@@ -124,8 +114,7 @@ function distinctTimes(times) {
|
|
|
124
114
|
seen.set(`${h}:${t}`, [h, t]);
|
|
125
115
|
return [...seen.values()].sort((a, b) => a[1] - b[1] || a[0] - b[0]);
|
|
126
116
|
}
|
|
127
|
-
// Only the keys that carry something
|
|
128
|
-
// is the line 0.13.0 printed, field for field.
|
|
117
|
+
// Only the keys that carry something.
|
|
129
118
|
function withTimes(line, cached, recorded) {
|
|
130
119
|
return {
|
|
131
120
|
...line,
|
|
@@ -134,15 +123,11 @@ function withTimes(line, cached, recorded) {
|
|
|
134
123
|
};
|
|
135
124
|
}
|
|
136
125
|
/**
|
|
137
|
-
* `cached` is every witness time the packs cache (5.6.6
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
* Moved from `cli.ts` unchanged: same inputs, same three states
|
|
144
|
-
* (`WitnessState`), same rendering. The CLI's `case` command still calls this
|
|
145
|
-
* exact function, so its witness line is unchanged.
|
|
126
|
+
* `cached` is every witness time the packs cache (5.6.6). Where no lookup ran,
|
|
127
|
+
* each is printed labelled not checked. Where one ran, each time the public
|
|
128
|
+
* record matched is printed as the record's, each time no lookup settled stays
|
|
129
|
+
* labelled not checked, and a time the record contradicts makes the line read
|
|
130
|
+
* `differs`.
|
|
146
131
|
*/
|
|
147
132
|
export function witnessLine(onChain, cached = []) {
|
|
148
133
|
if (!onChain.checked) {
|
|
@@ -172,7 +157,7 @@ export function witnessLine(onChain, cached = []) {
|
|
|
172
157
|
if (!contradicted.includes(reason))
|
|
173
158
|
contradicted.push(reason);
|
|
174
159
|
}
|
|
175
|
-
if (onChain.verdict === "
|
|
160
|
+
if (onChain.verdict === "differs") {
|
|
176
161
|
return withTimes({ state: "differs", reasons: contradicted, services }, unsettled, recorded);
|
|
177
162
|
}
|
|
178
163
|
if (onChain.verdict === "confirmed") {
|
|
@@ -190,34 +175,22 @@ export function witnessLine(onChain, cached = []) {
|
|
|
190
175
|
return withTimes({ state: "not_checked", reasons, services }, unsettled, recorded);
|
|
191
176
|
}
|
|
192
177
|
/**
|
|
193
|
-
* The public-record lookup the CLI runs with `--gateways`,
|
|
194
|
-
* consumer that is not the CLI can run the SAME lookup rather than copy it
|
|
195
|
-
* (proof#200; the copy this closes is verify-page#70's `src/lib/verify.ts`).
|
|
178
|
+
* The public-record lookup the CLI runs with `--gateways`, for non-CLI callers.
|
|
196
179
|
*
|
|
197
|
-
* `packs` is every pack in the drop
|
|
198
|
-
*
|
|
199
|
-
* `not_checked` or `no_public_record`. `options.fetchImpl` is the one seam a
|
|
200
|
-
* network call goes through, a browser page supplies its own `fetchImpl`;
|
|
201
|
-
* with none given this falls back to the ambient global `fetch`, so a
|
|
202
|
-
* browser page and a test can each supply their own and Node's `fetch` is
|
|
203
|
-
* never assumed where a caller passed something else.
|
|
180
|
+
* `packs` is every pack in the drop; `gateways` is empty for an offline reading,
|
|
181
|
+
* which makes no network call and answers `not_checked` or `no_public_record`.
|
|
204
182
|
*
|
|
205
|
-
* `state` is `confirmed` only about the
|
|
206
|
-
* pack names. It says nothing about whether the pack itself verifies
|
|
207
|
-
*
|
|
208
|
-
* `confirmed` apart from the pack's own verdict (proof#201).
|
|
183
|
+
* `state` is `confirmed` only about the bytes: the public record holds what a
|
|
184
|
+
* pack names. It says nothing about whether the pack itself verifies, so a
|
|
185
|
+
* caller must never show `confirmed` apart from the pack's own verdict.
|
|
209
186
|
*
|
|
210
|
-
* Never throws. Every input
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
* `not_checked` rather than escape as an exception.
|
|
187
|
+
* Never throws. Every input (a malformed pack, a non-string gateway, a
|
|
188
|
+
* misbehaving `fetchImpl`) is untrusted, and anything it cannot make sense of
|
|
189
|
+
* settles as `not_checked`.
|
|
214
190
|
*/
|
|
215
191
|
export async function lookupPublicRecord(packs, gateways, options = {}) {
|
|
216
192
|
try {
|
|
217
|
-
//
|
|
218
|
-
// check, which is not the same claim as "the packs it handed in name no
|
|
219
|
-
// witness" (`no_public_record`, below). Checked first, and unconditionally,
|
|
220
|
-
// so a caller than mishandles an empty drop never reads it as confirmed.
|
|
193
|
+
// Zero packs is the caller handing in nothing, not packs that name no witness (`no_public_record`). Checked first so an empty drop never reads as confirmed.
|
|
221
194
|
if (packs.length === 0) {
|
|
222
195
|
const reasons = [...WITNESS_NOT_LOOKED_UP.reasons];
|
|
223
196
|
return {
|
|
@@ -235,23 +208,12 @@ export async function lookupPublicRecord(packs, gateways, options = {}) {
|
|
|
235
208
|
]);
|
|
236
209
|
const onChain = await onChainHalfForWitnessCount(rows, gateways, options);
|
|
237
210
|
const line = witnessLine(onChain.half, caches.flat());
|
|
238
|
-
//
|
|
239
|
-
//
|
|
240
|
-
//
|
|
241
|
-
//
|
|
242
|
-
//
|
|
243
|
-
//
|
|
244
|
-
// a second reading of the bundle.
|
|
245
|
-
//
|
|
246
|
-
// A pack that does NOT verify (a broken wrapper signature, `bundle: null`,
|
|
247
|
-
// garbage, an unrecognised body type) also names zero witnesses, by
|
|
248
|
-
// construction: `verifyEvidenceBundle` never reports a checkpoint or a
|
|
249
|
-
// stamp for a bundle it could not authenticate. That is not "nothing to
|
|
250
|
-
// check yet", it is a pack this lookup could not read, so `no_public_record`
|
|
251
|
-
// is reserved for a pack whose wrapper genuinely verifies
|
|
252
|
-
// (`signatureOk && bodyHashOk && status !== "failed"`) and that carries no
|
|
253
|
-
// cached witness time either (a cache entry names something to check).
|
|
254
|
-
// Anything else that would otherwise qualify reads `not_checked` instead.
|
|
211
|
+
// `no_public_record`: every pack names zero witnesses, so nothing could be
|
|
212
|
+
// confirmed or contradicted. Reserved for packs whose wrapper verifies
|
|
213
|
+
// (`signatureOk && bodyHashOk && status !== "failed"`) and that carry no
|
|
214
|
+
// cached witness time: a pack that fails to verify also names zero
|
|
215
|
+
// witnesses, and that is a pack this lookup could not read, so it reads
|
|
216
|
+
// `not_checked`.
|
|
255
217
|
const noWitnesses = onChain.witnessCounts.every((n) => n === 0);
|
|
256
218
|
const everyPackVerifies = onChain.verifies.every((v) => v);
|
|
257
219
|
const noCacheRead = caches.every((c) => c.length === 0);
|
|
@@ -262,19 +224,13 @@ export async function lookupPublicRecord(packs, gateways, options = {}) {
|
|
|
262
224
|
reasons: line.reasons,
|
|
263
225
|
services: line.services,
|
|
264
226
|
...(line.cached ? { cached: line.cached } : {}),
|
|
265
|
-
// `recorded`
|
|
266
|
-
// time; it never rides alongside anything but a `confirmed` verdict, so
|
|
267
|
-
// a pack whose wrapper does not verify can never surface a cached time
|
|
268
|
-
// as though the record had confirmed it.
|
|
227
|
+
// `recorded` rides only with a `confirmed` verdict, so a pack whose wrapper does not verify never surfaces a cached time as record-confirmed.
|
|
269
228
|
...(state === "confirmed" && line.recorded ? { recorded: line.recorded } : {}),
|
|
270
229
|
rendered: renderWitnessLine({ ...line, state: state === "no_public_record" ? "not_checked" : state }),
|
|
271
230
|
};
|
|
272
231
|
}
|
|
273
232
|
catch (e) {
|
|
274
|
-
// Untrusted input all the way down
|
|
275
|
-
// caller's `fetchImpl`. Anything this function or what it calls cannot
|
|
276
|
-
// make sense of settles `not_checked` rather than throw out of an export a
|
|
277
|
-
// browser page calls directly.
|
|
233
|
+
// Untrusted input all the way down (a gateway's answer, a pack's shape, a `fetchImpl`): settle `not_checked` rather than throw out of an export a page calls directly.
|
|
278
234
|
const reason = e instanceof Error ? `the lookup did not settle: ${e.message}` : "the lookup did not settle";
|
|
279
235
|
const reasons = [reason];
|
|
280
236
|
return {
|
|
@@ -285,15 +241,9 @@ export async function lookupPublicRecord(packs, gateways, options = {}) {
|
|
|
285
241
|
};
|
|
286
242
|
}
|
|
287
243
|
}
|
|
288
|
-
//
|
|
289
|
-
//
|
|
290
|
-
// `
|
|
291
|
-
// OFFLINE reading. This wrapper reads each pack's witness count, and whether
|
|
292
|
-
// its wrapper verifies, the same way `onChainHalf` does, via
|
|
293
|
-
// `verifyEvidenceBundle`: an OFFLINE parse (`gateways: []`), so it costs no
|
|
294
|
-
// extra request whether or not a lookup runs, and `verifies` is never itself
|
|
295
|
-
// a statement about the public record, only about the pack's own signature
|
|
296
|
-
// and `body_hash`.
|
|
244
|
+
// Reads each pack's witness count and whether its wrapper verifies, via an
|
|
245
|
+
// offline `verifyEvidenceBundle` parse (`gateways: []`), so it costs no request.
|
|
246
|
+
// `verifies` is about the pack's own signature and `body_hash`, never the public record.
|
|
297
247
|
async function onChainHalfForWitnessCount(packs, gateways, options) {
|
|
298
248
|
const witnessCounts = [];
|
|
299
249
|
const verifies = [];
|
package/dist/zip-reader.d.ts
CHANGED
|
@@ -1,57 +1,42 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The one ZIP reader `case` uses, for a case file named on the command line.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* a central directory that contradicts a local header, a name that is not
|
|
8
|
-
* UTF-8, data after the end of a deflate stream. Where either library would
|
|
9
|
-
* have made a choice, this module refuses instead.
|
|
4
|
+
* Node has no ZIP reader. This one refuses where two libraries would disagree
|
|
5
|
+
* (evidence-bundle.md 5.6.1). It reads the central directory and each entry
|
|
6
|
+
* through its local header, stored and deflate only.
|
|
10
7
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* reads, entry by entry: an encrypted entry, a symbolic link, a method other
|
|
20
|
-
* than stored or deflate, and a name that is absolute, holds a backslash or a
|
|
21
|
-
* NUL, or has an empty, `.` or `..` segment.
|
|
8
|
+
* It refuses the whole archive for: no end-of-central-directory record, ZIP64,
|
|
9
|
+
* more than one disk, an entry placed outside the archive, a local header that
|
|
10
|
+
* contradicts its central entry, a size or CRC-32 that does not match, two
|
|
11
|
+
* entries with one name, a name that is not UTF-8, more than MAX_ZIP_ENTRIES
|
|
12
|
+
* entries or MAX_ZIP_BYTES bytes, or a name nested deeper than MAX_ZIP_DEPTH.
|
|
13
|
+
* It reports without reading, per entry: an encrypted entry, a symbolic link,
|
|
14
|
+
* another method, and a name that is absolute, holds a backslash or NUL, or has
|
|
15
|
+
* an empty, `.` or `..` segment.
|
|
22
16
|
*
|
|
23
|
-
* Pure: bytes in, entries out.
|
|
24
|
-
* splits.
|
|
17
|
+
* Pure: bytes in, entries out.
|
|
25
18
|
*/
|
|
26
|
-
/** More entries than this refuse the archive
|
|
19
|
+
/** More entries than this refuse the archive. */
|
|
27
20
|
export declare const MAX_ZIP_ENTRIES = 50000;
|
|
28
21
|
/** More uncompressed bytes than this, across every entry, refuse the archive. */
|
|
29
22
|
export declare const MAX_ZIP_BYTES: number;
|
|
30
23
|
/**
|
|
31
24
|
* An archive file larger than this is refused before it is read: the
|
|
32
|
-
* uncompressed cap
|
|
33
|
-
*
|
|
34
|
-
* size on disk, so the archive is never read whole to find out it is too big.
|
|
25
|
+
* uncompressed cap plus room for headers and framing. The caller checks the
|
|
26
|
+
* size on disk.
|
|
35
27
|
*/
|
|
36
28
|
export declare const MAX_ZIP_ARCHIVE_BYTES: number;
|
|
37
29
|
/** A name nested deeper than this many folders refuses the archive. */
|
|
38
30
|
export declare const MAX_ZIP_DEPTH = 32;
|
|
39
|
-
/** The archive cannot be read as a case file. `message` is the whole report
|
|
31
|
+
/** The archive cannot be read as a case file. `message` is the whole report. */
|
|
40
32
|
export declare class ZipReadError extends Error {
|
|
41
33
|
constructor(message: string);
|
|
42
34
|
}
|
|
43
|
-
/**
|
|
44
|
-
* One file entry. `refused` is why the entry is reported and not read, or
|
|
45
|
-
* `null`; `data` is its bytes where it was read.
|
|
46
|
-
*/
|
|
35
|
+
/** One file entry. `refused` is why it is reported and not read, or `null`; `data` is set where it was read. */
|
|
47
36
|
export interface ZipEntry {
|
|
48
37
|
name: string;
|
|
49
38
|
refused: string | null;
|
|
50
39
|
data: Uint8Array | null;
|
|
51
40
|
}
|
|
52
|
-
/**
|
|
53
|
-
* Every FILE entry of a ZIP archive, in central-directory order. A directory
|
|
54
|
-
* entry (a name ending in `/`) is not a file and is not returned. Throws
|
|
55
|
-
* `ZipReadError`.
|
|
56
|
-
*/
|
|
41
|
+
/** Every file entry of a ZIP archive, in central-directory order (directory entries are skipped). Throws `ZipReadError`. */
|
|
57
42
|
export declare function readZip(data: Uint8Array): ZipEntry[];
|
package/dist/zip-reader.js
CHANGED
|
@@ -1,39 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The one ZIP reader `case` uses, for a case file named on the command line.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* a central directory that contradicts a local header, a name that is not
|
|
8
|
-
* UTF-8, data after the end of a deflate stream. Where either library would
|
|
9
|
-
* have made a choice, this module refuses instead.
|
|
4
|
+
* Node has no ZIP reader. This one refuses where two libraries would disagree
|
|
5
|
+
* (evidence-bundle.md 5.6.1). It reads the central directory and each entry
|
|
6
|
+
* through its local header, stored and deflate only.
|
|
10
7
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* reads, entry by entry: an encrypted entry, a symbolic link, a method other
|
|
20
|
-
* than stored or deflate, and a name that is absolute, holds a backslash or a
|
|
21
|
-
* NUL, or has an empty, `.` or `..` segment.
|
|
8
|
+
* It refuses the whole archive for: no end-of-central-directory record, ZIP64,
|
|
9
|
+
* more than one disk, an entry placed outside the archive, a local header that
|
|
10
|
+
* contradicts its central entry, a size or CRC-32 that does not match, two
|
|
11
|
+
* entries with one name, a name that is not UTF-8, more than MAX_ZIP_ENTRIES
|
|
12
|
+
* entries or MAX_ZIP_BYTES bytes, or a name nested deeper than MAX_ZIP_DEPTH.
|
|
13
|
+
* It reports without reading, per entry: an encrypted entry, a symbolic link,
|
|
14
|
+
* another method, and a name that is absolute, holds a backslash or NUL, or has
|
|
15
|
+
* an empty, `.` or `..` segment.
|
|
22
16
|
*
|
|
23
|
-
* Pure: bytes in, entries out.
|
|
24
|
-
* splits.
|
|
17
|
+
* Pure: bytes in, entries out.
|
|
25
18
|
*/
|
|
26
19
|
import { inflateRawSync } from "node:zlib";
|
|
27
20
|
import { utf8Strict } from "./verifier.js";
|
|
28
|
-
/** More entries than this refuse the archive
|
|
21
|
+
/** More entries than this refuse the archive. */
|
|
29
22
|
export const MAX_ZIP_ENTRIES = 50_000;
|
|
30
23
|
/** More uncompressed bytes than this, across every entry, refuse the archive. */
|
|
31
24
|
export const MAX_ZIP_BYTES = 2 ** 30;
|
|
32
25
|
/**
|
|
33
26
|
* An archive file larger than this is refused before it is read: the
|
|
34
|
-
* uncompressed cap
|
|
35
|
-
*
|
|
36
|
-
* size on disk, so the archive is never read whole to find out it is too big.
|
|
27
|
+
* uncompressed cap plus room for headers and framing. The caller checks the
|
|
28
|
+
* size on disk.
|
|
37
29
|
*/
|
|
38
30
|
export const MAX_ZIP_ARCHIVE_BYTES = MAX_ZIP_BYTES + 256 * 2 ** 20;
|
|
39
31
|
/** A name nested deeper than this many folders refuses the archive. */
|
|
@@ -44,7 +36,7 @@ const LOCAL = 0x04034b50;
|
|
|
44
36
|
const S_IFMT = 0o170000;
|
|
45
37
|
const S_IFLNK = 0o120000;
|
|
46
38
|
const UNIX = 3;
|
|
47
|
-
/** The archive cannot be read as a case file. `message` is the whole report
|
|
39
|
+
/** The archive cannot be read as a case file. `message` is the whole report. */
|
|
48
40
|
export class ZipReadError extends Error {
|
|
49
41
|
constructor(message) {
|
|
50
42
|
super(message);
|
|
@@ -89,18 +81,13 @@ function sameBytes(a, b) {
|
|
|
89
81
|
return false;
|
|
90
82
|
return true;
|
|
91
83
|
}
|
|
92
|
-
/**
|
|
93
|
-
* Every FILE entry of a ZIP archive, in central-directory order. A directory
|
|
94
|
-
* entry (a name ending in `/`) is not a file and is not returned. Throws
|
|
95
|
-
* `ZipReadError`.
|
|
96
|
-
*/
|
|
84
|
+
/** Every file entry of a ZIP archive, in central-directory order (directory entries are skipped). Throws `ZipReadError`. */
|
|
97
85
|
export function readZip(data) {
|
|
98
86
|
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
99
87
|
const n = data.length;
|
|
100
88
|
const u32 = (at) => view.getUint32(at, true);
|
|
101
89
|
const u16 = (at) => view.getUint16(at, true);
|
|
102
|
-
//
|
|
103
|
-
// 65535, searched backwards so the LAST signature wins.
|
|
90
|
+
// 22 bytes plus a comment of at most 65535, searched backwards so the last signature wins.
|
|
104
91
|
let eocd = -1;
|
|
105
92
|
const lowest = Math.max(0, n - 22 - 0xffff);
|
|
106
93
|
for (let at = n - 22; at >= lowest; at--) {
|
|
@@ -202,9 +189,7 @@ export function readZip(data) {
|
|
|
202
189
|
body = packed;
|
|
203
190
|
}
|
|
204
191
|
else {
|
|
205
|
-
//
|
|
206
|
-
// input bytes the stream consumed. Anything left over is data after the
|
|
207
|
-
// end of the deflate stream, which Python's `unused_data` refuses too.
|
|
192
|
+
// Bytes left over after the end of the deflate stream are refused.
|
|
208
193
|
let result;
|
|
209
194
|
try {
|
|
210
195
|
result = inflateRawSync(packed, {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sanning/proof",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "TypeScript kernel of the Sanning verification stack: RFC 8785 (JCS) canonicalization, SHA-256, and Ed25519 verification for Verifiable Event Envelopes. Full-family verifier (inline + external commitment); accepts sanning.
|
|
3
|
+
"version": "0.20.0",
|
|
4
|
+
"description": "TypeScript kernel of the Sanning verification stack: RFC 8785 (JCS) canonicalization, SHA-256, and Ed25519 verification for Verifiable Event Envelopes. Full-family verifier (inline + external commitment); accepts sanning.events/v2. Conformance-gated byte-for-byte against the test-vectors corpus.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"sideEffects": false,
|
|
@@ -52,5 +52,13 @@
|
|
|
52
52
|
"merkle",
|
|
53
53
|
"rfc9162"
|
|
54
54
|
],
|
|
55
|
-
"
|
|
55
|
+
"repository": {
|
|
56
|
+
"type": "git",
|
|
57
|
+
"url": "git+https://github.com/sanning-io/proof.git",
|
|
58
|
+
"directory": "ts"
|
|
59
|
+
},
|
|
60
|
+
"homepage": "https://github.com/sanning-io/proof#readme",
|
|
61
|
+
"bugs": {
|
|
62
|
+
"url": "https://github.com/sanning-io/proof/issues"
|
|
63
|
+
}
|
|
56
64
|
}
|