@mikeargento/bitgraph-audit 0.8.0 → 0.10.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 +8 -2
- package/dist/audit.d.ts +9 -6
- package/dist/audit.d.ts.map +1 -1
- package/dist/audit.js +34 -8
- package/dist/audit.js.map +1 -1
- package/dist/ceilings.d.ts.map +1 -1
- package/dist/ceilings.js +1 -0
- package/dist/ceilings.js.map +1 -1
- package/dist/cli.js +109 -21
- package/dist/cli.js.map +1 -1
- package/dist/exports.d.ts +39 -0
- package/dist/exports.d.ts.map +1 -0
- package/dist/exports.js +374 -0
- package/dist/exports.js.map +1 -0
- package/dist/floors.d.ts +23 -0
- package/dist/floors.d.ts.map +1 -0
- package/dist/floors.js +203 -0
- package/dist/floors.js.map +1 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/ingest.d.ts +2 -0
- package/dist/ingest.d.ts.map +1 -1
- package/dist/ingest.js +193 -19
- package/dist/ingest.js.map +1 -1
- package/dist/report-json.d.ts.map +1 -1
- package/dist/report-json.js +30 -0
- package/dist/report-json.js.map +1 -1
- package/dist/report-md.d.ts.map +1 -1
- package/dist/report-md.js +315 -25
- package/dist/report-md.js.map +1 -1
- package/dist/temporal.d.ts +12 -0
- package/dist/temporal.d.ts.map +1 -1
- package/dist/temporal.js +245 -41
- package/dist/temporal.js.map +1 -1
- package/dist/types.d.ts +348 -7
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -2
- package/src/__tests__/base-floor.test.ts +405 -0
- package/src/audit.ts +36 -8
- package/src/ceilings.ts +1 -0
- package/src/cli.ts +117 -22
- package/src/exports.ts +482 -0
- package/src/floors.ts +242 -0
- package/src/index.ts +20 -0
- package/src/ingest.ts +207 -18
- package/src/report-json.ts +30 -0
- package/src/report-md.ts +353 -29
- package/src/temporal.ts +279 -48
- package/src/types.ts +341 -6
package/dist/exports.js
ADDED
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
// Copyright (c) 2024-2026 Argento Computing Inc. Licensed under the MIT License. See LICENSE.
|
|
2
|
+
/**
|
|
3
|
+
* Exports (bitgraph-export/1) through the audit.
|
|
4
|
+
*
|
|
5
|
+
* An export is one JSON file that, with the file it covers, checks a tree/1
|
|
6
|
+
* BitGraph with nothing of BitGraph's required: the signed proof, the tree's
|
|
7
|
+
* 84-byte root document, one member's evidence (a member export) or the
|
|
8
|
+
* whole list of leaves (the owner's export), the floor block's header, and
|
|
9
|
+
* the ceiling and the settlement, each carried or pending. Ingest finds every
|
|
10
|
+
* export by its format field, wherever it sits; the proof it carries joins
|
|
11
|
+
* the proof analysis like any other. This stage checks each export with
|
|
12
|
+
* verifyExport from bitgraph-verify, once per file in the bundle it covers:
|
|
13
|
+
*
|
|
14
|
+
* member export the files whose SHA-256 is the leaf's artifact digest
|
|
15
|
+
* (the committed bytes) or its origin digest (the original);
|
|
16
|
+
* owner export every file whose SHA-256 is any leaf's artifact or origin;
|
|
17
|
+
* no such file one run without a file: the claims about the file read
|
|
18
|
+
* NOT_CARRIED, which is never a failure.
|
|
19
|
+
*
|
|
20
|
+
* verifyExport's claims are reported exactly as it states them, each with
|
|
21
|
+
* what it rests on. Claims every run states alike are kept once on the
|
|
22
|
+
* export (ExportCheck.claims); each run keeps its own (in practice the ones
|
|
23
|
+
* about its file) with their places in verifyExport's order, and
|
|
24
|
+
* exportRunClaims puts a run's whole list back together. The three time
|
|
25
|
+
* claims are kept apart, never merged: the floor (the committed bytes were
|
|
26
|
+
* finished after the block the proof signs: Ethereum block N for an anchor
|
|
27
|
+
* floor, Base block N for a Base floor, enclave v10; an as-is leaf has no
|
|
28
|
+
* floor), the ceiling on Base (the record existed by Base block B, provisional until B is
|
|
29
|
+
* checked against Base) and the ceiling on Ethereum (the record existed by
|
|
30
|
+
* Ethereum block H). An export with any FALSE claim fails the audit (exit
|
|
31
|
+
* bit 1), as a bad proof does; its attestation claims count, because an
|
|
32
|
+
* export is checked as one self-contained object, as a carrier is.
|
|
33
|
+
*
|
|
34
|
+
* Owner exports at scale: verifyExport rebuilds the whole tree from the
|
|
35
|
+
* owner's list on every call, so checking m files against a list of n
|
|
36
|
+
* leaves as given costs n x m. When the list holds (its claim tree.leaves is
|
|
37
|
+
* TRUE, checked once), each file's member evidence is derived from the list
|
|
38
|
+
* exactly as verifyExport derives it, verifyExport runs on that member form,
|
|
39
|
+
* and the list's claim is put back where verifyExport places it: the same
|
|
40
|
+
* run, for the cost of one path. When the list fails, files are checked as
|
|
41
|
+
* given, within a budget of rebuilt leaves (asGivenLeafBudget).
|
|
42
|
+
*
|
|
43
|
+
* Zero network: no lookup is made unless an embedder passes its own
|
|
44
|
+
* (ExportAuditOptions.lookups). The CLI never does, so every confirmed claim
|
|
45
|
+
* reads UNDETERMINED ("not checked").
|
|
46
|
+
*/
|
|
47
|
+
import { base64ToBytes, buildTreeMemberEvidence, bytesToHex, decodeTreeLeaves, LEAF_PLACEMENTS, MerkleTree, parseExport, parseTreeMemberEvidence, treeLeafHash, verifyExport, } from "@mikeargento/bitgraph-verify";
|
|
48
|
+
import { streamArtifactsByHash } from "./ingest.js";
|
|
49
|
+
/** Default for ExportAuditOptions.asGivenLeafBudget: on the order of 15 s of rebuilding on a laptop. */
|
|
50
|
+
export const DEFAULT_AS_GIVEN_LEAF_BUDGET = 2_000_000;
|
|
51
|
+
/** The claim verifyExport places the owner's list check before, in the same run. */
|
|
52
|
+
const LIST_CLAIM_ID = "tree.leaves";
|
|
53
|
+
const LIST_CLAIM_BEFORE = "spec.pin";
|
|
54
|
+
/**
|
|
55
|
+
* A run's whole claim list, in verifyExport's order: the export's common
|
|
56
|
+
* claims with the run's own claims put back at their positions.
|
|
57
|
+
*/
|
|
58
|
+
export function exportRunClaims(check, run) {
|
|
59
|
+
const total = check.claims.length + run.claims.length;
|
|
60
|
+
const out = new Array(total);
|
|
61
|
+
for (const own of run.claims) {
|
|
62
|
+
const { position, ...claim } = own;
|
|
63
|
+
if (position >= 0 && position < total && out[position] === undefined)
|
|
64
|
+
out[position] = claim;
|
|
65
|
+
}
|
|
66
|
+
let next = 0;
|
|
67
|
+
for (let i = 0; i < total; i++) {
|
|
68
|
+
if (out[i] === undefined)
|
|
69
|
+
out[i] = check.claims[next++];
|
|
70
|
+
}
|
|
71
|
+
return out.filter((c) => c !== undefined);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Check every export in the bundle with verifyExport, per covered file.
|
|
75
|
+
* Deterministic: exports in observation order, runs in the order of their
|
|
76
|
+
* covered files (sorted by first path).
|
|
77
|
+
*/
|
|
78
|
+
export async function verifyExports(ingest, options = {}) {
|
|
79
|
+
const files = ingest.exports ?? [];
|
|
80
|
+
if (files.length === 0)
|
|
81
|
+
return { checks: [] };
|
|
82
|
+
const pins = {
|
|
83
|
+
...(options.pcr0 !== undefined ? { pcr0: [...options.pcr0] } : {}),
|
|
84
|
+
...(options.ceilingWriter !== undefined ? { ceilingWriter: options.ceilingWriter } : {}),
|
|
85
|
+
...(options.baseChainId !== undefined ? { baseChainId: options.baseChainId } : {}),
|
|
86
|
+
};
|
|
87
|
+
const common = {
|
|
88
|
+
pins,
|
|
89
|
+
...(options.extraSpecHashes !== undefined ? { extraSpecHashes: options.extraSpecHashes } : {}),
|
|
90
|
+
...(options.lookups !== undefined ? { lookups: options.lookups } : {}),
|
|
91
|
+
};
|
|
92
|
+
const budget = options.asGivenLeafBudget ?? DEFAULT_AS_GIVEN_LEAF_BUDGET;
|
|
93
|
+
const plans = files.map((file) => planExport(file, ingest, budget));
|
|
94
|
+
// Owner exports first check their list once: the per-file runs depend on it.
|
|
95
|
+
for (const plan of plans) {
|
|
96
|
+
if (plan.kind !== "owner" || plan.covered.length === 0 || plan.exp === null)
|
|
97
|
+
continue;
|
|
98
|
+
const r0 = await runExport(plan, plan.exp, null, common);
|
|
99
|
+
const listClaim = r0.claims.find((c) => c.id === LIST_CLAIM_ID);
|
|
100
|
+
if (listClaim?.result === "TRUE" && plan.leaves !== null) {
|
|
101
|
+
plan.fromList = { tree: new MerkleTree(plan.leaves.map(treeLeafHash)), listClaim };
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
plan.noFileRun = r0;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Every covered file's bytes, read once, whichever exports cover it.
|
|
108
|
+
const byHash = new Map();
|
|
109
|
+
for (const plan of plans) {
|
|
110
|
+
for (const c of plan.covered) {
|
|
111
|
+
const list = byHash.get(c.sha256Hex);
|
|
112
|
+
if (list === undefined)
|
|
113
|
+
byHash.set(c.sha256Hex, [plan]);
|
|
114
|
+
else
|
|
115
|
+
list.push(plan);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
for await (const artifact of streamArtifactsByHash(ingest, byHash.keys())) {
|
|
119
|
+
for (const plan of byHash.get(artifact.sha256Hex) ?? []) {
|
|
120
|
+
const entry = plan.coveredByHash.get(artifact.sha256Hex);
|
|
121
|
+
if (entry === undefined || plan.runs.has(artifact.sha256Hex))
|
|
122
|
+
continue;
|
|
123
|
+
const run = await runForFile(plan, entry.covered, entry.source, artifact.bytes, common);
|
|
124
|
+
if (run === null) {
|
|
125
|
+
plan.unchecked.set(artifact.sha256Hex, {
|
|
126
|
+
file: entry.covered,
|
|
127
|
+
reason: `not checked one by one: checking a file against this export as given rebuilds the owner's whole list ` +
|
|
128
|
+
`(${withCommas(plan.leaves?.length ?? 0)} leaves) each time, and the budget of ${withCommas(budget)} ` +
|
|
129
|
+
`rebuilt leaves ran out; the runs that were made carry the list's own claim (tree.leaves)`,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
plan.runs.set(artifact.sha256Hex, run);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const checks = [];
|
|
138
|
+
for (const plan of plans) {
|
|
139
|
+
for (const c of plan.covered) {
|
|
140
|
+
if (!plan.runs.has(c.sha256Hex) && !plan.unchecked.has(c.sha256Hex)) {
|
|
141
|
+
plan.unchecked.set(c.sha256Hex, { file: c, reason: "not checked: the file's bytes could not be re-read from the bundle" });
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const runs = plan.covered.map((c) => plan.runs.get(c.sha256Hex)).filter((r) => r !== undefined);
|
|
145
|
+
if (runs.length === 0) {
|
|
146
|
+
runs.push(plan.noFileRun ?? (await runExport(plan, plan.exp ?? plan.file.json, null, common)));
|
|
147
|
+
}
|
|
148
|
+
checks.push(assemble(plan, runs));
|
|
149
|
+
}
|
|
150
|
+
return { checks };
|
|
151
|
+
}
|
|
152
|
+
// ---------------------------------------------------------------------------
|
|
153
|
+
// Planning: which bundle files an export covers
|
|
154
|
+
// ---------------------------------------------------------------------------
|
|
155
|
+
function planExport(file, ingest, budget) {
|
|
156
|
+
const plan = {
|
|
157
|
+
file,
|
|
158
|
+
exp: null,
|
|
159
|
+
digests: new Map(),
|
|
160
|
+
leaves: null,
|
|
161
|
+
covered: [],
|
|
162
|
+
coveredByHash: new Map(),
|
|
163
|
+
runs: new Map(),
|
|
164
|
+
unchecked: new Map(),
|
|
165
|
+
intern: new Map(),
|
|
166
|
+
asGivenLeft: Number.POSITIVE_INFINITY,
|
|
167
|
+
};
|
|
168
|
+
if (file.status !== "ok")
|
|
169
|
+
return plan;
|
|
170
|
+
const exp = parseExport(file.json);
|
|
171
|
+
if (exp === null)
|
|
172
|
+
return plan;
|
|
173
|
+
plan.exp = exp;
|
|
174
|
+
const tree = exp.tree;
|
|
175
|
+
const hasMember = tree["member"] !== undefined;
|
|
176
|
+
const hasLeaves = tree["leaves"] !== undefined;
|
|
177
|
+
plan.kind = hasLeaves ? "owner" : hasMember ? "member" : "root-only";
|
|
178
|
+
if (hasLeaves) {
|
|
179
|
+
const bytes = typeof tree["leaves"] === "string" ? base64ToBytes(tree["leaves"]) : null;
|
|
180
|
+
const leaves = bytes === null ? null : decodeTreeLeaves(bytes);
|
|
181
|
+
plan.leaves = leaves;
|
|
182
|
+
if (leaves !== null) {
|
|
183
|
+
const names = tree["names"];
|
|
184
|
+
const named = Array.isArray(names) && names.length === leaves.length && names.every((n) => typeof n === "string") ? names : null;
|
|
185
|
+
leaves.forEach((leaf, i) => addLeaf(plan.digests, leaf, i, named?.[i], "list"));
|
|
186
|
+
// Checking as given rebuilds the whole list per file.
|
|
187
|
+
plan.asGivenLeft = Math.max(1, Math.floor(budget / Math.max(1, leaves.length)));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (hasMember) {
|
|
191
|
+
// After the list: a digest the list already places keeps the list's leaf, as verifyExport does.
|
|
192
|
+
const ev = parseTreeMemberEvidence(tree["member"]);
|
|
193
|
+
if (ev !== null)
|
|
194
|
+
addLeaf(plan.digests, ev.leaf, ev.index, undefined, "member");
|
|
195
|
+
}
|
|
196
|
+
for (const artifact of ingest.artifacts) {
|
|
197
|
+
const match = plan.digests.get(artifact.sha256Hex);
|
|
198
|
+
if (match === undefined)
|
|
199
|
+
continue;
|
|
200
|
+
const covered = {
|
|
201
|
+
sha256Hex: artifact.sha256Hex,
|
|
202
|
+
paths: [...artifact.paths],
|
|
203
|
+
byteLength: artifact.byteLength,
|
|
204
|
+
leafIndex: match.leafIndex,
|
|
205
|
+
placement: match.placement,
|
|
206
|
+
matchedAs: match.matchedAs,
|
|
207
|
+
...(match.nameInExport !== undefined ? { nameInExport: match.nameInExport } : {}),
|
|
208
|
+
};
|
|
209
|
+
plan.covered.push(covered);
|
|
210
|
+
plan.coveredByHash.set(artifact.sha256Hex, { covered, source: match.source });
|
|
211
|
+
}
|
|
212
|
+
plan.covered.sort((a, b) => cmp(a.paths[0] ?? "", b.paths[0] ?? "") || cmp(a.sha256Hex, b.sha256Hex));
|
|
213
|
+
return plan;
|
|
214
|
+
}
|
|
215
|
+
/** Record a leaf's two digests, keeping the first leaf in tree order for each (verifyExport's findIndex). */
|
|
216
|
+
function addLeaf(digests, leaf, index, name, source) {
|
|
217
|
+
const artifact = bytesToHex(leaf.artifact);
|
|
218
|
+
const origin = bytesToHex(leaf.origin);
|
|
219
|
+
const placement = LEAF_PLACEMENTS[leaf.placement] ?? null;
|
|
220
|
+
const at = { leafIndex: index, placement, source, ...(name !== undefined ? { nameInExport: name } : {}) };
|
|
221
|
+
if (!digests.has(artifact))
|
|
222
|
+
digests.set(artifact, { ...at, matchedAs: artifact === origin ? "as-is" : "committed-bytes" });
|
|
223
|
+
if (origin !== artifact && !digests.has(origin))
|
|
224
|
+
digests.set(origin, { ...at, matchedAs: "original" });
|
|
225
|
+
}
|
|
226
|
+
// ---------------------------------------------------------------------------
|
|
227
|
+
// Runs
|
|
228
|
+
// ---------------------------------------------------------------------------
|
|
229
|
+
async function runForFile(plan, covered, source, bytes, common) {
|
|
230
|
+
const exp = plan.exp;
|
|
231
|
+
if (plan.fromList !== undefined && plan.leaves !== null && source === "list" && covered.leafIndex !== null) {
|
|
232
|
+
// The owner's list holds: derive this file's member evidence from it
|
|
233
|
+
// exactly as verifyExport does internally (the first leaf in tree order
|
|
234
|
+
// whose committed or original digest is the file's, its path in the tree
|
|
235
|
+
// the whole list builds), run on that member form, and put the list's
|
|
236
|
+
// claim back where verifyExport places it. A test holds this equal to the
|
|
237
|
+
// as-given run.
|
|
238
|
+
const k = covered.leafIndex;
|
|
239
|
+
const evidence = buildTreeMemberEvidence(plan.leaves[k], k, plan.leaves.length, plan.fromList.tree.path(k));
|
|
240
|
+
const memberForm = { ...exp, tree: { rootDocument: exp.tree.rootDocument, member: evidence } };
|
|
241
|
+
const run = await runExport(plan, memberForm, covered, common, bytes);
|
|
242
|
+
const at = run.claims.findIndex((c) => c.id === LIST_CLAIM_BEFORE);
|
|
243
|
+
run.claims.splice(at < 0 ? run.claims.length : at, 0, plan.fromList.listClaim);
|
|
244
|
+
return run;
|
|
245
|
+
}
|
|
246
|
+
if (plan.leaves !== null) {
|
|
247
|
+
if (plan.asGivenLeft <= 0)
|
|
248
|
+
return null;
|
|
249
|
+
plan.asGivenLeft--;
|
|
250
|
+
}
|
|
251
|
+
return runExport(plan, exp, covered, common, bytes);
|
|
252
|
+
}
|
|
253
|
+
/** One verifyExport call. A verifier that throws fails the export closed. */
|
|
254
|
+
async function runExport(plan, input, file, common, bytes) {
|
|
255
|
+
let r;
|
|
256
|
+
try {
|
|
257
|
+
r = await verifyExport(input, bytes !== undefined ? { ...common, bytes } : common);
|
|
258
|
+
}
|
|
259
|
+
catch (err) {
|
|
260
|
+
const detail = `verifyExport could not complete on this export (${err instanceof Error ? err.message : String(err)}); the audit fails it closed`;
|
|
261
|
+
return {
|
|
262
|
+
file,
|
|
263
|
+
verdict: "FALSE",
|
|
264
|
+
claims: [intern(plan, { id: "verifier", name: "The verifier completed its checks", result: "FALSE", restsOn: "", detail, level: "offline" })],
|
|
265
|
+
member: null,
|
|
266
|
+
times: { floor: null, ceilingBase: null, ceilingEthereum: null },
|
|
267
|
+
floorCovers: null,
|
|
268
|
+
reading: "This export could not be checked: the verifier stopped on it. The audit counts that as a failure.",
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
const claims = r.claims.map((c) => intern(plan, { id: c.id, name: c.name, result: c.result, restsOn: c.restsOn, detail: c.detail, level: c.level }));
|
|
272
|
+
const isMember = claims.some((c) => c.id === "bytes.member" && c.result === "TRUE");
|
|
273
|
+
return {
|
|
274
|
+
file,
|
|
275
|
+
verdict: r.verdict,
|
|
276
|
+
claims,
|
|
277
|
+
member: r.member === null ? null : { ...r.member },
|
|
278
|
+
times: copyTimes(r.times),
|
|
279
|
+
floorCovers: file === null || !isMember || r.member === null ? null : r.member.placement === "as-is" ? "record" : "content",
|
|
280
|
+
reading: r.reading,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
function intern(plan, claim) {
|
|
284
|
+
const key = claimKey(claim);
|
|
285
|
+
const known = plan.intern.get(key);
|
|
286
|
+
if (known !== undefined)
|
|
287
|
+
return known;
|
|
288
|
+
plan.intern.set(key, claim);
|
|
289
|
+
return claim;
|
|
290
|
+
}
|
|
291
|
+
function claimKey(c) {
|
|
292
|
+
return `${c.id}\u0000${c.result}\u0000${c.level}\u0000${c.restsOn}\u0000${c.detail}`;
|
|
293
|
+
}
|
|
294
|
+
function copyTimes(t) {
|
|
295
|
+
return {
|
|
296
|
+
floor: t.floor === null
|
|
297
|
+
? null
|
|
298
|
+
: { ...(t.floor.chain === "base" ? { chain: "base" } : {}), blockNumber: t.floor.blockNumber, blockHash: t.floor.blockHash, blockTimestamp: t.floor.blockTimestamp },
|
|
299
|
+
ceilingBase: t.ceilingBase === null
|
|
300
|
+
? null
|
|
301
|
+
: { blockNumber: t.ceilingBase.blockNumber, blockHash: t.ceilingBase.blockHash, blockTimestamp: t.ceilingBase.blockTimestamp, provisional: t.ceilingBase.provisional },
|
|
302
|
+
ceilingEthereum: t.ceilingEthereum === null
|
|
303
|
+
? null
|
|
304
|
+
: { blockNumber: t.ceilingEthereum.blockNumber, blockHash: t.ceilingEthereum.blockHash, blockTimestamp: t.ceilingEthereum.blockTimestamp },
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
// ---------------------------------------------------------------------------
|
|
308
|
+
// The check
|
|
309
|
+
// ---------------------------------------------------------------------------
|
|
310
|
+
function assemble(plan, full) {
|
|
311
|
+
const { file } = plan;
|
|
312
|
+
// Claims every run states alike (interned: the same object), in the first run's order.
|
|
313
|
+
const inRuns = new Map();
|
|
314
|
+
for (const run of full)
|
|
315
|
+
for (const c of new Set(run.claims))
|
|
316
|
+
inRuns.set(c, (inRuns.get(c) ?? 0) + 1);
|
|
317
|
+
const isCommon = (c) => inRuns.get(c) === full.length;
|
|
318
|
+
const claims = full[0].claims.filter(isCommon);
|
|
319
|
+
const runs = full.map((run) => ({
|
|
320
|
+
file: run.file,
|
|
321
|
+
verdict: run.verdict,
|
|
322
|
+
claims: run.claims.flatMap((c, position) => (isCommon(c) ? [] : [{ ...c, position }])),
|
|
323
|
+
member: run.member,
|
|
324
|
+
floorCovers: run.floorCovers,
|
|
325
|
+
reading: run.reading,
|
|
326
|
+
}));
|
|
327
|
+
const failedClaims = [];
|
|
328
|
+
for (const run of full) {
|
|
329
|
+
for (const c of run.claims)
|
|
330
|
+
if (c.result === "FALSE" && !failedClaims.includes(c.id))
|
|
331
|
+
failedClaims.push(c.id);
|
|
332
|
+
}
|
|
333
|
+
const verdict = failedClaims.length > 0 || full.some((r) => r.verdict === "FALSE")
|
|
334
|
+
? "FALSE"
|
|
335
|
+
: full.some((r) => r.verdict === "UNDETERMINED")
|
|
336
|
+
? "UNDETERMINED"
|
|
337
|
+
: "TRUE";
|
|
338
|
+
const status = file.status === "ok" ? "checked" : file.status;
|
|
339
|
+
const reason = file.status === "malformed"
|
|
340
|
+
? `declares ${file.format} but lacks an export's structure (a proof object and tree.rootDocument)`
|
|
341
|
+
: file.status === "unsupported-format"
|
|
342
|
+
? `format "${file.format}" is not bitgraph-export/1`
|
|
343
|
+
: file.status === "too-large"
|
|
344
|
+
? "opens an export but is larger than the audit's cap for one export's JSON (IngestLimits.maxExportJsonBytes)"
|
|
345
|
+
: undefined;
|
|
346
|
+
return {
|
|
347
|
+
path: file.path,
|
|
348
|
+
fileSha256Hex: file.fileSha256Hex,
|
|
349
|
+
format: file.format,
|
|
350
|
+
status,
|
|
351
|
+
...(reason !== undefined ? { reason } : {}),
|
|
352
|
+
...(plan.kind !== undefined ? { kind: plan.kind } : {}),
|
|
353
|
+
...(file.proofHash !== undefined ? { proofHash: file.proofHash } : {}),
|
|
354
|
+
// A rejected file is never judged TRUE; its exit bit comes from its status.
|
|
355
|
+
verdict: status === "checked" ? verdict : verdict === "FALSE" ? "FALSE" : "UNDETERMINED",
|
|
356
|
+
failedClaims,
|
|
357
|
+
// The time claims do not depend on the file, so every run that completed states the same.
|
|
358
|
+
times: (full.find((r) => !r.claims.some((c) => c.id === "verifier")) ?? full[0]).times,
|
|
359
|
+
claims,
|
|
360
|
+
files: plan.covered,
|
|
361
|
+
runs,
|
|
362
|
+
...(plan.kind === "owner" && plan.covered.length > 0 ? { runMode: plan.fromList !== undefined ? "member-from-list" : "as-given" } : {}),
|
|
363
|
+
...(plan.unchecked.size > 0
|
|
364
|
+
? { unchecked: plan.covered.filter((c) => plan.unchecked.has(c.sha256Hex)).map((c) => plan.unchecked.get(c.sha256Hex)) }
|
|
365
|
+
: {}),
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
function withCommas(n) {
|
|
369
|
+
return String(n).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
370
|
+
}
|
|
371
|
+
function cmp(a, b) {
|
|
372
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
373
|
+
}
|
|
374
|
+
//# sourceMappingURL=exports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exports.js","sourceRoot":"","sources":["../src/exports.ts"],"names":[],"mappings":"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"}
|
package/dist/floors.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { FloorProblem, IngestResult, SignedFloorRecord } from "./types.js";
|
|
2
|
+
/** A Base floor that bounds the proof signing it. */
|
|
3
|
+
export interface FloorEvidence {
|
|
4
|
+
/** The proof that signs the floor. */
|
|
5
|
+
proofHash: string;
|
|
6
|
+
blockNumber: number;
|
|
7
|
+
blockHash: string;
|
|
8
|
+
/** Unix seconds: the signed time, equal to the checked header's when one was carried. */
|
|
9
|
+
timestamp: number;
|
|
10
|
+
timeSource: "header" | "signed";
|
|
11
|
+
}
|
|
12
|
+
export interface FloorReading {
|
|
13
|
+
/** Base floors usable as not-before bounds, keyed by the proof that signs them. */
|
|
14
|
+
bounds: Map<string, FloorEvidence>;
|
|
15
|
+
/** Every Base floor a proof signs, bounding or withheld, in observation order. */
|
|
16
|
+
records: SignedFloorRecord[];
|
|
17
|
+
problems: FloorProblem[];
|
|
18
|
+
}
|
|
19
|
+
/** Read every Base floor the bundle's proofs sign, and the headers that check them. */
|
|
20
|
+
export declare function readSignedFloors(ingest: IngestResult): FloorReading;
|
|
21
|
+
/** The sentence a Base floor bound states about its block time, shared by the reports. */
|
|
22
|
+
export declare function baseFloorTimeSentence(blockNumber: number | string, timestamp: number, timeSource: "header" | "signed"): string;
|
|
23
|
+
//# sourceMappingURL=floors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"floors.d.ts","sourceRoot":"","sources":["../src/floors.ts"],"names":[],"mappings":"AA+CA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAiB,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE/F,qDAAqD;AACrD,MAAM,WAAW,aAAa;IAC5B,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,yFAAyF;IACzF,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,QAAQ,GAAG,QAAQ,CAAC;CACjC;AAED,MAAM,WAAW,YAAY;IAC3B,mFAAmF;IACnF,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACnC,kFAAkF;IAClF,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,QAAQ,EAAE,YAAY,EAAE,CAAC;CAC1B;AAqBD,uFAAuF;AACvF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,GAAG,YAAY,CAkJnE;AAED,0FAA0F;AAC1F,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAI9H"}
|
package/dist/floors.js
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
// Copyright (c) 2024-2026 Argento Computing Inc. Licensed under the MIT License. See LICENSE.
|
|
2
|
+
/**
|
|
3
|
+
* bitgraph-audit signed floors (enclave v10)
|
|
4
|
+
*
|
|
5
|
+
* From enclave v10 a proof's floor is a Base block the enclave signs into the
|
|
6
|
+
* proof as commit.slotFloor { chain: "base", evmChainId: 8453, blockNumber,
|
|
7
|
+
* blockHash, blockTimestamp }, one per proof, instead of an Ethereum anchor
|
|
8
|
+
* (commit.slotAnchor, read through the anchor proofs of the chain). Every
|
|
9
|
+
* floor is read through signedFloorOf from bitgraph-verify, which refuses a
|
|
10
|
+
* proof that signs both kinds: such a proof is ambiguous and nothing is read
|
|
11
|
+
* from it as a floor.
|
|
12
|
+
*
|
|
13
|
+
* What a Base floor gives the temporal stage: a NOT-BEFORE for the proof that
|
|
14
|
+
* signs it, grounded in block-hash unpredictability (the block hash did not
|
|
15
|
+
* exist before the block, and the proof signs it). Never a not-after: a later
|
|
16
|
+
* proof's floor block can predate this proof, so a floor bounds nothing
|
|
17
|
+
* before it.
|
|
18
|
+
*
|
|
19
|
+
* The block time. Base mainnet stamps every block by its height, and the
|
|
20
|
+
* enclave signs the time it read from a header it hashed itself. When the
|
|
21
|
+
* bundle carries that header (a floor header file, bitgraph-floor-header/1,
|
|
22
|
+
* as the carrier/3 unpacker writes it; or the floor inside a ceiling file or
|
|
23
|
+
* an export) it is checked with checkFloorHeader: keccak-256 to the signed
|
|
24
|
+
* hash, the signed number and time, Base mainnet's schedule. Without one the
|
|
25
|
+
* time is the signed one, which must still be on Base mainnet's schedule for
|
|
26
|
+
* the signed number, and confirming the block itself needs a Base lookup,
|
|
27
|
+
* which this offline audit never makes.
|
|
28
|
+
*
|
|
29
|
+
* A floor stamped after the proof's own attestation document is withheld as a
|
|
30
|
+
* bound (floorTimeIsBound): the record did not exist before that block, but
|
|
31
|
+
* the block's time cannot be a "not before" for a record already attested.
|
|
32
|
+
*
|
|
33
|
+
* Proofs with no slotFloor are not read here at all: bundles from before the
|
|
34
|
+
* cutover audit exactly as before.
|
|
35
|
+
*/
|
|
36
|
+
import { baseHeaderFields, checkFloorHeader, evmHexToBytes, floorTimeIsBound, onBaseSchedule, signedFloorOf, } from "@mikeargento/bitgraph-verify";
|
|
37
|
+
import { attestationTimestampMs } from "./attestation.js";
|
|
38
|
+
function record(value) {
|
|
39
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
40
|
+
}
|
|
41
|
+
function iso(unix) {
|
|
42
|
+
return new Date(unix * 1000).toISOString();
|
|
43
|
+
}
|
|
44
|
+
function firstPath(p) {
|
|
45
|
+
return p.sources[0]?.path;
|
|
46
|
+
}
|
|
47
|
+
/** Read every Base floor the bundle's proofs sign, and the headers that check them. */
|
|
48
|
+
export function readSignedFloors(ingest) {
|
|
49
|
+
const problems = [];
|
|
50
|
+
const records = [];
|
|
51
|
+
const bounds = new Map();
|
|
52
|
+
// The Base floors the proofs sign, by block hash (to match header files).
|
|
53
|
+
const signedHashes = new Set();
|
|
54
|
+
for (const p of ingest.proofs) {
|
|
55
|
+
const f = p.proof.commit?.slotFloor;
|
|
56
|
+
if (f !== undefined && typeof f.blockHash === "string")
|
|
57
|
+
signedHashes.add(f.blockHash.toLowerCase());
|
|
58
|
+
}
|
|
59
|
+
// Headers in the bundle, by the hash their bytes compute to.
|
|
60
|
+
const headers = new Map();
|
|
61
|
+
const add = (hash, c) => {
|
|
62
|
+
const list = headers.get(hash) ?? [];
|
|
63
|
+
list.push(c);
|
|
64
|
+
headers.set(hash, list);
|
|
65
|
+
};
|
|
66
|
+
for (const file of ingest.floorHeaders ?? []) {
|
|
67
|
+
const json = file.json;
|
|
68
|
+
const header = json["header"];
|
|
69
|
+
const fields = typeof header === "string" ? baseHeaderFields(header) : null;
|
|
70
|
+
if (json["chain"] !== "base" || fields === null) {
|
|
71
|
+
problems.push({
|
|
72
|
+
code: "floor-header-malformed",
|
|
73
|
+
path: file.path,
|
|
74
|
+
message: json["chain"] !== "base"
|
|
75
|
+
? `the floor header file names chain ${JSON.stringify(json["chain"])}; only a Base header (chain "base") is a floor header`
|
|
76
|
+
: "the floor header file carries no readable Base block header",
|
|
77
|
+
});
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const declared = typeof json["blockHash"] === "string" ? json["blockHash"].toLowerCase() : undefined;
|
|
81
|
+
if (declared !== undefined && declared !== fields.blockHash) {
|
|
82
|
+
problems.push({
|
|
83
|
+
code: "floor-header-mismatch",
|
|
84
|
+
path: file.path,
|
|
85
|
+
message: `the header in this file hashes to ${fields.blockHash}, not to the block it names (${declared})`,
|
|
86
|
+
});
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (!signedHashes.has(fields.blockHash)) {
|
|
90
|
+
problems.push({
|
|
91
|
+
code: "floor-header-unmatched",
|
|
92
|
+
path: file.path,
|
|
93
|
+
message: `the header is Base block ${fields.blockNumber} (${fields.blockHash}), which no proof in this bundle signs as its floor`,
|
|
94
|
+
});
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
add(fields.blockHash, { path: file.path, raw: evmHexToBytes(header), fromFloorFile: true });
|
|
98
|
+
}
|
|
99
|
+
// The floor a ceiling file or an export carries, when it is a Base header.
|
|
100
|
+
const carried = (path, floor, field) => {
|
|
101
|
+
if (floor === null || floor["chain"] !== "base" || typeof floor[field] !== "string")
|
|
102
|
+
return;
|
|
103
|
+
const fields = baseHeaderFields(floor[field]);
|
|
104
|
+
if (fields === null || !signedHashes.has(fields.blockHash))
|
|
105
|
+
return;
|
|
106
|
+
add(fields.blockHash, { path, raw: evmHexToBytes(floor[field]), fromFloorFile: false });
|
|
107
|
+
};
|
|
108
|
+
for (const c of ingest.ceilings ?? [])
|
|
109
|
+
carried(c.path, record(c.json["floor"]), "blockHeader");
|
|
110
|
+
for (const e of ingest.exports ?? [])
|
|
111
|
+
if (e.status === "ok")
|
|
112
|
+
carried(e.path, record(e.json["floor"]), "header");
|
|
113
|
+
for (const p of ingest.proofs) {
|
|
114
|
+
const commit = p.proof.commit;
|
|
115
|
+
if (commit === undefined || commit["slotFloor"] === undefined)
|
|
116
|
+
continue;
|
|
117
|
+
const path = firstPath(p);
|
|
118
|
+
let floor;
|
|
119
|
+
try {
|
|
120
|
+
floor = signedFloorOf(p.proof);
|
|
121
|
+
}
|
|
122
|
+
catch (e) {
|
|
123
|
+
const both = commit["slotAnchor"] !== undefined;
|
|
124
|
+
problems.push({
|
|
125
|
+
code: both ? "floor-ambiguous" : "floor-malformed",
|
|
126
|
+
proofHash: p.proofHash,
|
|
127
|
+
...(path !== undefined ? { path } : {}),
|
|
128
|
+
message: both
|
|
129
|
+
? "the proof signs two floors (commit.slotAnchor, an Ethereum anchor, and commit.slotFloor, a Base block); it is ambiguous and neither is read as its floor"
|
|
130
|
+
: `the proof's commit.slotFloor is not a Base floor: ${e.message}`,
|
|
131
|
+
});
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (floor === null || floor.chain !== "base" || floor.blockTimestamp === undefined)
|
|
135
|
+
continue;
|
|
136
|
+
const base = {
|
|
137
|
+
proofHash: p.proofHash,
|
|
138
|
+
chain: "base",
|
|
139
|
+
blockNumber: floor.blockNumber,
|
|
140
|
+
blockHash: floor.blockHash,
|
|
141
|
+
blockTimestamp: floor.blockTimestamp,
|
|
142
|
+
};
|
|
143
|
+
const withheld = (reason, header, headerPath) => {
|
|
144
|
+
records.push({ ...base, header, ...(headerPath !== undefined ? { headerPath } : {}), bound: "withheld", withheldReason: reason });
|
|
145
|
+
};
|
|
146
|
+
if (!onBaseSchedule(floor.blockNumber, floor.blockTimestamp)) {
|
|
147
|
+
const reason = `the signed time of Base block ${floor.blockNumber} (${floor.blockTimestamp}) is not Base mainnet's schedule for that block`;
|
|
148
|
+
problems.push({ code: "floor-off-schedule", proofHash: p.proofHash, ...(path !== undefined ? { path } : {}), message: reason });
|
|
149
|
+
withheld(reason, "not-carried");
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
// A header in the bundle for the signed block: every floor header file
|
|
153
|
+
// naming it must hold; the first that holds dates the floor.
|
|
154
|
+
let checkedPath;
|
|
155
|
+
let mismatch;
|
|
156
|
+
for (const c of headers.get(floor.blockHash) ?? []) {
|
|
157
|
+
const r = checkFloorHeader(floor, c.raw, "base");
|
|
158
|
+
if (r.ok) {
|
|
159
|
+
checkedPath ??= c.path;
|
|
160
|
+
}
|
|
161
|
+
else if (c.fromFloorFile) {
|
|
162
|
+
mismatch = `${c.path}: ${r.reason}`;
|
|
163
|
+
problems.push({
|
|
164
|
+
code: "floor-header-mismatch",
|
|
165
|
+
proofHash: p.proofHash,
|
|
166
|
+
path: c.path,
|
|
167
|
+
message: `the floor header does not match the Base floor the proof signs: ${r.reason}`,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
const header = checkedPath !== undefined ? "checked" : "not-carried";
|
|
172
|
+
if (mismatch !== undefined) {
|
|
173
|
+
withheld(`a floor header in the bundle contradicts the signed floor (${mismatch})`, header, checkedPath);
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
if (p.verification?.status === "failed") {
|
|
177
|
+
withheld("the proof does not verify, so the floor in it is not a signed one", header, checkedPath);
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
const attestedMs = attestationTimestampMs((p.proof.environment?.attestation?.reportB64) ?? "");
|
|
181
|
+
const timeOk = floorTimeIsBound(floor.blockTimestamp, attestedMs);
|
|
182
|
+
if (!timeOk.ok) {
|
|
183
|
+
withheld(timeOk.reason, header, checkedPath);
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
records.push({ ...base, header, ...(checkedPath !== undefined ? { headerPath: checkedPath } : {}), bound: "not-before" });
|
|
187
|
+
bounds.set(p.proofHash, {
|
|
188
|
+
proofHash: p.proofHash,
|
|
189
|
+
blockNumber: floor.blockNumber,
|
|
190
|
+
blockHash: floor.blockHash,
|
|
191
|
+
timestamp: floor.blockTimestamp,
|
|
192
|
+
timeSource: checkedPath !== undefined ? "header" : "signed",
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
return { bounds, records, problems };
|
|
196
|
+
}
|
|
197
|
+
/** The sentence a Base floor bound states about its block time, shared by the reports. */
|
|
198
|
+
export function baseFloorTimeSentence(blockNumber, timestamp, timeSource) {
|
|
199
|
+
return timeSource === "header"
|
|
200
|
+
? `Base block ${blockNumber} is stamped ${iso(timestamp)}; its header is in the bundle and was checked against the signed block hash, number and time.`
|
|
201
|
+
: `Base block ${blockNumber} is stamped ${iso(timestamp)} as the proof signs it, on Base mainnet's schedule for that block; no header for it is in the bundle, so confirming the block needs a Base lookup.`;
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=floors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"floors.js","sourceRoot":"","sources":["../src/floors.ts"],"names":[],"mappings":"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"}
|