@mikeargento/bitgraph-player 0.3.0 → 0.5.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 +40 -0
- package/SPEC.md +5 -2
- package/dist/__tests__/check.test.d.ts +2 -0
- package/dist/__tests__/check.test.d.ts.map +1 -0
- package/dist/__tests__/check.test.js +389 -0
- package/dist/__tests__/check.test.js.map +1 -0
- package/dist/check.d.ts +156 -0
- package/dist/check.d.ts.map +1 -0
- package/dist/check.js +640 -0
- package/dist/check.js.map +1 -0
- package/dist/cli.js +84 -15
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/verdict.d.ts +1 -1
- package/dist/verdict.js +1 -1
- package/dist-web/verify.html +159 -0
- package/package.json +10 -4
- package/src/__tests__/check.test.ts +451 -0
- package/src/__tests__/fixtures/declared-12010/proof.json +1 -0
- package/src/__tests__/fixtures/export-random-043/ethereum-anchors/anchor-after-witness.json +6 -0
- package/src/__tests__/fixtures/export-random-043/ethereum-anchors/anchor-after.json +43 -0
- package/src/__tests__/fixtures/export-random-043/ethereum-anchors/anchor-before-witness.json +6 -0
- package/src/__tests__/fixtures/export-random-043/ethereum-anchors/anchor-before.json +47 -0
- package/src/__tests__/fixtures/export-random-043/proof.json +38 -0
- package/src/__tests__/fixtures/export-random-043/random-043.txt +1 -0
- package/src/check.ts +873 -0
- package/src/cli.ts +82 -16
- package/src/index.ts +3 -0
- package/src/verdict.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikeargento/bitgraph-player",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Deterministic evaluation of causal rules over BitGraph proof bundles: a pure function from (rule, verified evidence) to a reproducible verdict.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
},
|
|
18
18
|
"files": [
|
|
19
19
|
"dist",
|
|
20
|
+
"dist-web",
|
|
20
21
|
"src",
|
|
21
22
|
"SPEC.md",
|
|
22
23
|
"README.md",
|
|
@@ -26,17 +27,22 @@
|
|
|
26
27
|
"build": "tsc",
|
|
27
28
|
"prepack": "tsc",
|
|
28
29
|
"typecheck": "tsc --noEmit",
|
|
29
|
-
"test": "tsc && node --test \"dist/__tests__/*.test.js\""
|
|
30
|
+
"test": "tsc && node --test \"dist/__tests__/*.test.js\"",
|
|
31
|
+
"build:web": "node scripts/build-verify-html.mjs --out ../folder/src/verify.html",
|
|
32
|
+
"typecheck:web": "tsc -p web/tsconfig.json"
|
|
30
33
|
},
|
|
31
34
|
"engines": {
|
|
32
35
|
"node": ">=20"
|
|
33
36
|
},
|
|
34
37
|
"dependencies": {
|
|
35
|
-
"@mikeargento/bitgraph-audit": "^0.1
|
|
36
|
-
"@mikeargento/bitgraph-verify": "^1.
|
|
38
|
+
"@mikeargento/bitgraph-audit": "^0.2.1",
|
|
39
|
+
"@mikeargento/bitgraph-verify": "^1.2.0"
|
|
37
40
|
},
|
|
38
41
|
"devDependencies": {
|
|
42
|
+
"@noble/curves": "^2.3.0",
|
|
39
43
|
"@types/node": "^20.0.0",
|
|
44
|
+
"buffer": "^6.0.3",
|
|
45
|
+
"esbuild": "^0.27.0",
|
|
40
46
|
"typescript": "^5.4.0"
|
|
41
47
|
}
|
|
42
48
|
}
|
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
// Copyright (c) 2024-2026 Mike Argento. Licensed under the MIT License. See LICENSE.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `check` tests.
|
|
5
|
+
*
|
|
6
|
+
* The real fixture is a genuine export from the production ledger: a
|
|
7
|
+
* 685-byte random text file, its proof (real Ed25519 signature, real AWS
|
|
8
|
+
* Nitro attestation, enclave v5 measurement), both bounding anchors, and
|
|
9
|
+
* both block-header witnesses. Copied verbatim from a BitGraph Folder
|
|
10
|
+
* export; read-only here, no ledger writes, no network.
|
|
11
|
+
*
|
|
12
|
+
* The parity test is the one that matters most: the same bundle ingested
|
|
13
|
+
* from disk (the CLI's path) and from memory (the browser page's path)
|
|
14
|
+
* must produce byte-identical reports, or the two fronts have drifted.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { describe, it, before, after } from "node:test";
|
|
18
|
+
import * as assert from "node:assert/strict";
|
|
19
|
+
import { spawnSync } from "node:child_process";
|
|
20
|
+
import { cp, mkdtemp, readFile, rm, writeFile, readdir } from "node:fs/promises";
|
|
21
|
+
import { tmpdir } from "node:os";
|
|
22
|
+
import { join, relative } from "node:path";
|
|
23
|
+
import { fileURLToPath } from "node:url";
|
|
24
|
+
import { ingestBundle, ingestEntries } from "@mikeargento/bitgraph-audit";
|
|
25
|
+
import type { AuditResult, BundleEntrySource } from "@mikeargento/bitgraph-audit";
|
|
26
|
+
import { buildCheckReport, checkIngest, renderCheckText, serializeCheckReport, KNOWN_ENCLAVE_MEASUREMENTS } from "../check.js";
|
|
27
|
+
import type { CheckReport } from "../check.js";
|
|
28
|
+
import { PLAYER_VERSION } from "../verdict.js";
|
|
29
|
+
import { digestFor, makeAudit } from "./fixtures.js";
|
|
30
|
+
|
|
31
|
+
const FIXTURE = fileURLToPath(new URL("../../src/__tests__/fixtures/export-random-043", import.meta.url));
|
|
32
|
+
const CLI_PATH = fileURLToPath(new URL("../cli.js", import.meta.url));
|
|
33
|
+
|
|
34
|
+
async function walk(root: string, rel = ""): Promise<string[]> {
|
|
35
|
+
const out: string[] = [];
|
|
36
|
+
const dir = rel === "" ? root : join(root, rel);
|
|
37
|
+
for (const entry of await readdir(dir, { withFileTypes: true })) {
|
|
38
|
+
const r = rel === "" ? entry.name : `${rel}/${entry.name}`;
|
|
39
|
+
if (entry.isDirectory()) out.push(...(await walk(root, r)));
|
|
40
|
+
else if (entry.isFile()) out.push(r);
|
|
41
|
+
}
|
|
42
|
+
return out;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function memoryEntriesOf(root: string): Promise<BundleEntrySource[]> {
|
|
46
|
+
const paths = await walk(root);
|
|
47
|
+
return paths.map((p) => ({
|
|
48
|
+
path: p,
|
|
49
|
+
open: () => readFile(join(root, ...p.split("/"))).then((b) => new Uint8Array(b)),
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Fill the audit sections makeAudit leaves empty so buildCheckReport can run over synthetic input. */
|
|
54
|
+
function complete(audit: AuditResult, overrides: Partial<AuditResult> = {}): AuditResult {
|
|
55
|
+
const a = audit as unknown as Record<string, unknown>;
|
|
56
|
+
return {
|
|
57
|
+
...audit,
|
|
58
|
+
anomalies: { anomalies: [], divergences: [], boundaryEntryPoints: [] },
|
|
59
|
+
authorities: { groups: [], anomalies: [], sharedSignersAcrossEpochs: [] },
|
|
60
|
+
anchors: { anchors: [], metadataOnlyProofHashes: [], findings: [] },
|
|
61
|
+
witnesses: { outcomes: [], findings: [] },
|
|
62
|
+
attestations: {
|
|
63
|
+
records: [],
|
|
64
|
+
findings: [],
|
|
65
|
+
counts: {
|
|
66
|
+
proofsWithDeclaredMeasurement: 0,
|
|
67
|
+
proofsWithDocument: 0,
|
|
68
|
+
documentsValidated: 0,
|
|
69
|
+
documentsFailed: 0,
|
|
70
|
+
pcr0Matches: 0,
|
|
71
|
+
pcr0Mismatches: 0,
|
|
72
|
+
userDataBound: 0,
|
|
73
|
+
userDataUnbound: 0,
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
...(a["temporal"] !== undefined ? {} : {}),
|
|
77
|
+
...overrides,
|
|
78
|
+
} as AuditResult;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
describe("check: real export fixture (disk)", () => {
|
|
82
|
+
let report: CheckReport;
|
|
83
|
+
before(async () => {
|
|
84
|
+
report = await checkIngest(await ingestBundle(FIXTURE));
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("is TRUE end to end: file, signature, attestation, enclave, both anchors, both witnesses", () => {
|
|
88
|
+
assert.equal(report.check, "bitgraph-check/1");
|
|
89
|
+
assert.equal(report.result, "TRUE");
|
|
90
|
+
assert.equal(report.recordings.length, 1);
|
|
91
|
+
assert.equal(report.anchors.length, 2);
|
|
92
|
+
const rec = report.recordings[0]!;
|
|
93
|
+
assert.equal(rec.result, "TRUE");
|
|
94
|
+
assert.equal(rec.filePath, "random-043.txt");
|
|
95
|
+
assert.deepEqual(
|
|
96
|
+
rec.lines.map((l) => [l.name, l.result]),
|
|
97
|
+
[
|
|
98
|
+
["file", "TRUE"],
|
|
99
|
+
["signature", "TRUE"],
|
|
100
|
+
["attestation", "TRUE"],
|
|
101
|
+
["enclave", "TRUE"],
|
|
102
|
+
]
|
|
103
|
+
);
|
|
104
|
+
for (const anchor of report.anchors) {
|
|
105
|
+
assert.equal(anchor.result, "TRUE");
|
|
106
|
+
assert.deepEqual(
|
|
107
|
+
anchor.lines.map((l) => [l.name, l.result]),
|
|
108
|
+
[
|
|
109
|
+
["signature", "TRUE"],
|
|
110
|
+
["witness", "TRUE"],
|
|
111
|
+
]
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
assert.equal(report.contradictions.length, 0);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("brackets the recording between the two verified block headers", () => {
|
|
118
|
+
const b = report.recordings[0]!.bounds;
|
|
119
|
+
assert.equal(b.status, "bracketed");
|
|
120
|
+
assert.equal(b.notBefore?.blockNumber, "25735831");
|
|
121
|
+
assert.equal(b.notAfter?.blockNumber, "25735832");
|
|
122
|
+
assert.match(b.detail, /after Ethereum block 25735831 and before block 25735832/);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("orders anchors by causal position, not file name", () => {
|
|
126
|
+
assert.deepEqual(
|
|
127
|
+
report.anchors.map((a) => a.blockNumber),
|
|
128
|
+
["25735831", "25735832"]
|
|
129
|
+
);
|
|
130
|
+
assert.equal(report.anchors[0]!.witnessPath, "ethereum-anchors/anchor-before-witness.json");
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("names the excerpt gaps as notes, never as verdicts", () => {
|
|
134
|
+
assert.ok(report.notes.some((n) => /causal positions? between the earliest and latest recording/.test(n)));
|
|
135
|
+
assert.ok(report.notes.some((n) => /link(s)? to a predecessor that is not in this bundle/.test(n)));
|
|
136
|
+
assert.equal(report.contradictions.length, 0);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it("states what it cannot check", () => {
|
|
140
|
+
assert.ok(report.notChecked.some((n) => /canonical/.test(n)));
|
|
141
|
+
assert.ok(report.notChecked.some((n) => /ledger/.test(n)));
|
|
142
|
+
assert.equal(report.network, "none");
|
|
143
|
+
assert.equal(report.evaluator.version, PLAYER_VERSION);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("recognizes the enclave v5 measurement from PINS.md", () => {
|
|
147
|
+
const enclave = report.recordings[0]!.lines.find((l) => l.name === "enclave")!;
|
|
148
|
+
assert.match(enclave.detail, /enclave v5/);
|
|
149
|
+
assert.equal(KNOWN_ENCLAVE_MEASUREMENTS.length, 4);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("serializes deterministically: no timestamps, no machine paths", async () => {
|
|
153
|
+
const again = await checkIngest(await ingestBundle(FIXTURE));
|
|
154
|
+
assert.equal(serializeCheckReport(again), serializeCheckReport(report));
|
|
155
|
+
const bytes = serializeCheckReport(report);
|
|
156
|
+
assert.ok(!bytes.includes(FIXTURE), "report must not contain the machine path");
|
|
157
|
+
assert.ok(!bytes.includes("startedAt"));
|
|
158
|
+
assert.ok(renderCheckText(report).startsWith("TRUE: this file was recorded at position 1576"));
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
describe("check: a DECLARED recording (agency proof)", () => {
|
|
163
|
+
/* Ledger position #12,010, the first declaration ever made on the public
|
|
164
|
+
chain (2026-08-18). It is here because these packages had no real agency
|
|
165
|
+
proof to test against, and two bugs lived in that gap at once:
|
|
166
|
+
|
|
167
|
+
1. the attestation stage compared user_data against computeProofHash,
|
|
168
|
+
the FROZEN SUBSET that excludes `actor`, instead of the hash of the
|
|
169
|
+
full signed body the enclave actually attested. Identical for every
|
|
170
|
+
proof without `actor`/`policy`, so every existing fixture passed;
|
|
171
|
+
2. the browser verifier's createVerify shim THREW on P-256 rather than
|
|
172
|
+
checking it, so verify.html reported a valid declared proof as
|
|
173
|
+
contradicting itself.
|
|
174
|
+
|
|
175
|
+
Both turned a good proof FALSE — the failure mode the three-valued rule
|
|
176
|
+
exists to prevent. Keep this fixture. */
|
|
177
|
+
const DECLARED = fileURLToPath(new URL("../../src/__tests__/fixtures/declared-12010", import.meta.url));
|
|
178
|
+
|
|
179
|
+
it("verifies: signature, attestation binding, and enclave identity all TRUE", async () => {
|
|
180
|
+
const report = await checkIngest(await ingestBundle(DECLARED));
|
|
181
|
+
const rec = report.recordings[0]!;
|
|
182
|
+
assert.equal(rec.lines.find((l) => l.name === "signature")!.result, "TRUE");
|
|
183
|
+
assert.equal(rec.lines.find((l) => l.name === "attestation")!.result, "TRUE");
|
|
184
|
+
assert.equal(rec.lines.find((l) => l.name === "enclave")!.result, "TRUE");
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it("is UNDETERMINED for want of the file, never FALSE", async () => {
|
|
188
|
+
const report = await checkIngest(await ingestBundle(DECLARED));
|
|
189
|
+
// The bundle holds no artifact, so the file line cannot decide. That is
|
|
190
|
+
// the only thing left open, and nothing here contradicts anything.
|
|
191
|
+
assert.equal(report.result, "UNDETERMINED");
|
|
192
|
+
assert.deepEqual(report.contradictions, []);
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
describe("check: disk and memory ingest produce byte-identical reports (the no-drift guarantee)", () => {
|
|
197
|
+
it("ingestEntries over the same files equals ingestBundle over the directory", async () => {
|
|
198
|
+
const fromDisk = await checkIngest(await ingestBundle(FIXTURE));
|
|
199
|
+
const fromMemory = await checkIngest(await ingestEntries(await memoryEntriesOf(FIXTURE)));
|
|
200
|
+
assert.equal(serializeCheckReport(fromMemory), serializeCheckReport(fromDisk));
|
|
201
|
+
assert.equal(fromMemory.result, "TRUE");
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it("memory ingest tolerates any supply order (entries are sorted by path)", async () => {
|
|
205
|
+
const entries = await memoryEntriesOf(FIXTURE);
|
|
206
|
+
const reversed = [...entries].reverse();
|
|
207
|
+
const a = await checkIngest(await ingestEntries(entries));
|
|
208
|
+
const b = await checkIngest(await ingestEntries(reversed));
|
|
209
|
+
assert.equal(serializeCheckReport(a), serializeCheckReport(b));
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it("memory ingest accepts whole bytes, promises, and chunk streams alike", async () => {
|
|
213
|
+
const paths = await walk(FIXTURE);
|
|
214
|
+
const entries: BundleEntrySource[] = [];
|
|
215
|
+
for (const [i, p] of paths.entries()) {
|
|
216
|
+
const bytes = new Uint8Array(await readFile(join(FIXTURE, ...p.split("/"))));
|
|
217
|
+
const open =
|
|
218
|
+
i % 3 === 0
|
|
219
|
+
? () => bytes
|
|
220
|
+
: i % 3 === 1
|
|
221
|
+
? () => Promise.resolve(bytes)
|
|
222
|
+
: () =>
|
|
223
|
+
(async function* () {
|
|
224
|
+
const half = Math.floor(bytes.length / 2);
|
|
225
|
+
yield bytes.subarray(0, half);
|
|
226
|
+
yield bytes.subarray(half);
|
|
227
|
+
})();
|
|
228
|
+
entries.push({ path: p, open });
|
|
229
|
+
}
|
|
230
|
+
const report = await checkIngest(await ingestEntries(entries));
|
|
231
|
+
assert.equal(report.result, "TRUE");
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
describe("check: what evidence in hand contradicts, and what it merely leaves open", () => {
|
|
236
|
+
let dir: string;
|
|
237
|
+
before(async () => {
|
|
238
|
+
dir = await mkdtemp(join(tmpdir(), "bitgraph-check-"));
|
|
239
|
+
});
|
|
240
|
+
after(async () => {
|
|
241
|
+
await rm(dir, { recursive: true, force: true });
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
async function copyFixture(name: string): Promise<string> {
|
|
245
|
+
const dest = join(dir, name);
|
|
246
|
+
await cp(FIXTURE, dest, { recursive: true });
|
|
247
|
+
return dest;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
it("an edited file is UNDETERMINED (not FALSE) with a note naming it: absence is not a verdict", async () => {
|
|
251
|
+
const d = await copyFixture("edited");
|
|
252
|
+
const p = join(d, "random-043.txt");
|
|
253
|
+
await writeFile(p, Buffer.concat([await readFile(p), Buffer.from("x")]));
|
|
254
|
+
const report = await checkIngest(await ingestBundle(d));
|
|
255
|
+
assert.equal(report.result, "UNDETERMINED");
|
|
256
|
+
const file = report.recordings[0]!.lines.find((l) => l.name === "file")!;
|
|
257
|
+
assert.equal(file.result, "UNDETERMINED");
|
|
258
|
+
assert.ok(report.notes.some((n) => /random-043\.txt/.test(n) && /bytes differ/.test(n)));
|
|
259
|
+
// Everything else about the recording still holds.
|
|
260
|
+
assert.equal(report.recordings[0]!.lines.find((l) => l.name === "signature")!.result, "TRUE");
|
|
261
|
+
assert.equal(report.recordings[0]!.lines.find((l) => l.name === "attestation")!.result, "TRUE");
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
it("a tampered signature is FALSE", async () => {
|
|
265
|
+
const d = await copyFixture("badsig");
|
|
266
|
+
const p = join(d, "proof.json");
|
|
267
|
+
const proof = JSON.parse(await readFile(p, "utf8")) as { signer: { signatureB64: string } };
|
|
268
|
+
const sig = Buffer.from(proof.signer.signatureB64, "base64");
|
|
269
|
+
sig[0] = sig[0]! ^ 1;
|
|
270
|
+
proof.signer.signatureB64 = sig.toString("base64");
|
|
271
|
+
await writeFile(p, JSON.stringify(proof));
|
|
272
|
+
const report = await checkIngest(await ingestBundle(d));
|
|
273
|
+
assert.equal(report.result, "FALSE");
|
|
274
|
+
assert.equal(report.recordings[0]!.lines.find((l) => l.name === "signature")!.result, "FALSE");
|
|
275
|
+
assert.match(report.summary, /^FALSE/);
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it("a tampered block header is FALSE on that anchor, and the bound it gave is withdrawn", async () => {
|
|
279
|
+
const d = await copyFixture("badwitness");
|
|
280
|
+
const p = join(d, "ethereum-anchors", "anchor-after-witness.json");
|
|
281
|
+
const w = JSON.parse(await readFile(p, "utf8")) as { headerRlpHex: string };
|
|
282
|
+
const h = w.headerRlpHex;
|
|
283
|
+
w.headerRlpHex = h.slice(0, -2) + (h.slice(-2) === "00" ? "11" : "00");
|
|
284
|
+
await writeFile(p, JSON.stringify(w));
|
|
285
|
+
const report = await checkIngest(await ingestBundle(d));
|
|
286
|
+
assert.equal(report.result, "FALSE");
|
|
287
|
+
const after = report.anchors.find((a) => a.blockNumber === "25735832")!;
|
|
288
|
+
assert.equal(after.lines.find((l) => l.name === "witness")!.result, "FALSE");
|
|
289
|
+
assert.equal(report.recordings[0]!.result, "TRUE", "the recording itself is still sound");
|
|
290
|
+
assert.equal(report.recordings[0]!.bounds.status, "lower-bounded");
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
it("proof plus file with no anchors is TRUE and unanchored", async () => {
|
|
294
|
+
const entries: BundleEntrySource[] = ["proof.json", "random-043.txt"].map((name) => ({
|
|
295
|
+
path: name,
|
|
296
|
+
open: () => readFile(join(FIXTURE, name)).then((b) => new Uint8Array(b)),
|
|
297
|
+
}));
|
|
298
|
+
const report = await checkIngest(await ingestEntries(entries));
|
|
299
|
+
assert.equal(report.result, "TRUE");
|
|
300
|
+
assert.equal(report.recordings[0]!.bounds.status, "unanchored");
|
|
301
|
+
assert.equal(report.anchors.length, 0);
|
|
302
|
+
assert.match(report.summary, /with no Ethereum bound in this bundle/);
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it("proof alone (no file) is UNDETERMINED: signature and attestation hold, binding to bytes does not", async () => {
|
|
306
|
+
const entries: BundleEntrySource[] = [
|
|
307
|
+
{ path: "proof.json", open: () => readFile(join(FIXTURE, "proof.json")).then((b) => new Uint8Array(b)) },
|
|
308
|
+
];
|
|
309
|
+
const report = await checkIngest(await ingestEntries(entries));
|
|
310
|
+
assert.equal(report.result, "UNDETERMINED");
|
|
311
|
+
const rec = report.recordings[0]!;
|
|
312
|
+
assert.equal(rec.lines.find((l) => l.name === "file")!.result, "UNDETERMINED");
|
|
313
|
+
assert.equal(rec.lines.find((l) => l.name === "signature")!.result, "TRUE");
|
|
314
|
+
assert.equal(rec.filePath, undefined);
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
it("without WebCrypto the attestation is UNDETERMINED with the reason, never FALSE", async () => {
|
|
318
|
+
const report = await checkIngest(await ingestBundle(FIXTURE), { webCryptoAvailable: false });
|
|
319
|
+
const rec = report.recordings[0]!;
|
|
320
|
+
assert.equal(rec.lines.find((l) => l.name === "attestation")!.result, "UNDETERMINED");
|
|
321
|
+
assert.match(rec.lines.find((l) => l.name === "attestation")!.detail, /WebCrypto/);
|
|
322
|
+
assert.equal(rec.lines.find((l) => l.name === "enclave")!.result, "UNDETERMINED");
|
|
323
|
+
assert.equal(report.result, "UNDETERMINED");
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
it("an empty bundle is UNDETERMINED and says so", async () => {
|
|
327
|
+
const report = await checkIngest(await ingestEntries([]));
|
|
328
|
+
assert.equal(report.result, "UNDETERMINED");
|
|
329
|
+
assert.match(report.summary, /no BitGraph proofs were found/);
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
describe("check: synthetic audit shapes", () => {
|
|
334
|
+
it("an unknown PCR0 is UNDETERMINED (outside this verifier's knowledge), never FALSE", () => {
|
|
335
|
+
const audit = complete(
|
|
336
|
+
makeAudit({
|
|
337
|
+
proofs: [{ name: "a", digestB64: digestFor("a"), epochId: "E", counter: "5", slotCounter: "4" }],
|
|
338
|
+
partitions: [{ epochId: "E", members: ["a"] }],
|
|
339
|
+
})
|
|
340
|
+
);
|
|
341
|
+
audit.attestations.records.push({
|
|
342
|
+
proofHash: "proofhash-a",
|
|
343
|
+
declaredMeasurementPresent: true,
|
|
344
|
+
declaredMeasurement: "ff".repeat(48),
|
|
345
|
+
documentPresent: true,
|
|
346
|
+
attestationFormat: "aws-nitro",
|
|
347
|
+
documentValidated: true,
|
|
348
|
+
checks: [],
|
|
349
|
+
attestedPcr0: "ff".repeat(48),
|
|
350
|
+
pcr0MatchesDeclared: true,
|
|
351
|
+
userDataBoundToProof: true,
|
|
352
|
+
});
|
|
353
|
+
const report = buildCheckReport(audit);
|
|
354
|
+
const rec = report.recordings[0]!;
|
|
355
|
+
assert.equal(rec.lines.find((l) => l.name === "attestation")!.result, "TRUE");
|
|
356
|
+
const enclave = rec.lines.find((l) => l.name === "enclave")!;
|
|
357
|
+
assert.equal(enclave.result, "UNDETERMINED");
|
|
358
|
+
assert.match(enclave.detail, /not among the BitGraph enclave measurements this verifier knows/);
|
|
359
|
+
assert.equal(report.result, "UNDETERMINED");
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
it("an attestation bound to some other proof is FALSE", () => {
|
|
363
|
+
const audit = complete(
|
|
364
|
+
makeAudit({
|
|
365
|
+
proofs: [{ name: "a", digestB64: digestFor("a"), epochId: "E", counter: "5" }],
|
|
366
|
+
partitions: [{ epochId: "E", members: ["a"] }],
|
|
367
|
+
})
|
|
368
|
+
);
|
|
369
|
+
audit.attestations.records.push({
|
|
370
|
+
proofHash: "proofhash-a",
|
|
371
|
+
declaredMeasurementPresent: true,
|
|
372
|
+
documentPresent: true,
|
|
373
|
+
documentValidated: true,
|
|
374
|
+
checks: [],
|
|
375
|
+
attestedPcr0: KNOWN_ENCLAVE_MEASUREMENTS[3]!.pcr0,
|
|
376
|
+
pcr0MatchesDeclared: true,
|
|
377
|
+
userDataBoundToProof: false,
|
|
378
|
+
});
|
|
379
|
+
const report = buildCheckReport(audit);
|
|
380
|
+
assert.equal(report.recordings[0]!.lines.find((l) => l.name === "attestation")!.result, "FALSE");
|
|
381
|
+
assert.equal(report.result, "FALSE");
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
it("structural contradictions surface as FALSE while excerpt gaps stay notes", () => {
|
|
385
|
+
const audit = complete(
|
|
386
|
+
makeAudit({
|
|
387
|
+
proofs: [
|
|
388
|
+
{ name: "a", digestB64: digestFor("a"), epochId: "E", counter: "5" },
|
|
389
|
+
{ name: "b", digestB64: digestFor("b"), epochId: "E", counter: "5" },
|
|
390
|
+
],
|
|
391
|
+
partitions: [{ epochId: "E", members: ["a", "b"] }],
|
|
392
|
+
})
|
|
393
|
+
);
|
|
394
|
+
audit.anomalies.anomalies.push(
|
|
395
|
+
{ code: "unexplained-counter-positions", proofHashes: [], message: "gap", details: { count: "3", ranges: [], positions: [], truncated: false } },
|
|
396
|
+
{ code: "chain-break-missing", proofHashes: ["proofhash-a"], message: "missing pred", details: {} },
|
|
397
|
+
{ code: "counter-collision", proofHashes: ["proofhash-a", "proofhash-b"], message: "two commits at position 5" }
|
|
398
|
+
);
|
|
399
|
+
const report = buildCheckReport(audit);
|
|
400
|
+
assert.equal(report.contradictions.length, 1);
|
|
401
|
+
assert.match(report.contradictions[0]!.detail, /^counter-collision/);
|
|
402
|
+
assert.ok(report.notes.some((n) => /3 causal positions/.test(n)));
|
|
403
|
+
assert.equal(report.result, "FALSE");
|
|
404
|
+
});
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
describe("check: CLI", () => {
|
|
408
|
+
it("prints the human report and exits 0 on the real fixture", () => {
|
|
409
|
+
const r = spawnSync(process.execPath, [CLI_PATH, "check", FIXTURE], { encoding: "utf8" });
|
|
410
|
+
assert.equal(r.status, 0, r.stderr);
|
|
411
|
+
assert.match(r.stdout, /^TRUE: this file was recorded at position 1576/);
|
|
412
|
+
assert.match(r.stdout, /Result: TRUE/);
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
it("--json prints the bitgraph-check/1 report", () => {
|
|
416
|
+
const r = spawnSync(process.execPath, [CLI_PATH, "check", FIXTURE, "--json"], { encoding: "utf8" });
|
|
417
|
+
assert.equal(r.status, 0, r.stderr);
|
|
418
|
+
const parsed = JSON.parse(r.stdout) as CheckReport;
|
|
419
|
+
assert.equal(parsed.check, "bitgraph-check/1");
|
|
420
|
+
assert.equal(parsed.result, "TRUE");
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
it("accepts a list of files and ingests them in memory", () => {
|
|
424
|
+
const r = spawnSync(
|
|
425
|
+
process.execPath,
|
|
426
|
+
[CLI_PATH, "check", join(FIXTURE, "proof.json"), join(FIXTURE, "random-043.txt")],
|
|
427
|
+
{ encoding: "utf8" }
|
|
428
|
+
);
|
|
429
|
+
assert.equal(r.status, 0, r.stderr);
|
|
430
|
+
assert.match(r.stdout, /no Ethereum bound in this bundle/);
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
it("exits 2 for UNDETERMINED (proof alone) and 3 for a missing path", () => {
|
|
434
|
+
const u = spawnSync(process.execPath, [CLI_PATH, "check", join(FIXTURE, "proof.json")], { encoding: "utf8" });
|
|
435
|
+
assert.equal(u.status, 2, u.stderr);
|
|
436
|
+
const e = spawnSync(process.execPath, [CLI_PATH, "check", join(FIXTURE, "does-not-exist")], { encoding: "utf8" });
|
|
437
|
+
assert.equal(e.status, 3);
|
|
438
|
+
assert.match(e.stderr, /cannot read bundle/);
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
it("evaluate and init reject --json (it belongs to check only)", () => {
|
|
442
|
+
const r = spawnSync(process.execPath, [CLI_PATH, "init", join(FIXTURE, "random-043.txt"), "--json"], { encoding: "utf8" });
|
|
443
|
+
assert.equal(r.status, 3);
|
|
444
|
+
assert.match(r.stderr, /usage:/);
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
it("the relative path helper is unused by the report (paths are bundle-relative only)", () => {
|
|
448
|
+
// Guard against a future report field leaking absolute paths.
|
|
449
|
+
assert.equal(relative(FIXTURE, join(FIXTURE, "proof.json")), "proof.json");
|
|
450
|
+
});
|
|
451
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version": "bitgraph/1", "artifact": {"hashAlg": "sha256", "digestB64": "szEkIOHMuIaOXlqVG9uqKvaKtmnYmklfzOjEldzFP2E="}, "commit": {"nonceB64": "05pT2TUMA2mJ0iBsQPkOaKFIUa0i4Ta6wdNkqS3jef4=", "counter": "12010", "slotCounter": "12009", "slotHashB64": "VbOoREc4tcmNwFFYmtfenUZ04LNkjP02wQN2okIi81Y=", "epochId": "plJ+9/nhhVEvDE4X4rCjJI+zys0fIov3XT114+mQIpk=", "prevB64": "3TzjHBZWqTMte6FE0BZ0SM7hrcRhFv29Sl4NMf/ZvBs=", "chainId": "bitgraph:main"}, "signer": {"publicKeyB64": "tmp21VjPay+EhaMwmrFLfdjZo2KIjjT7VDqjmm27wHI=", "signatureB64": "96dTfH4EYq1pRvS7zAhVZuiCLsfrlur0QkA4dfkRQZtbkQ8dgebEQn85TOdvvPtk2YYh9pP0k46HWrZuOOYlBg=="}, "environment": {"enforcement": "measured-tee", "measurement": "6483cedffed74680ffb287507744a398b288c3fb943eb3f2e4fe889f8b60b3d575ad8942350360b69a1bd7bf713df27f", "attestation": {"format": "aws-nitro", "reportB64": "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"}}, "slotAllocation": {"version": "bitgraph/slot/1", "nonceB64": "05pT2TUMA2mJ0iBsQPkOaKFIUa0i4Ta6wdNkqS3jef4=", "counter": "12009", "epochId": "plJ+9/nhhVEvDE4X4rCjJI+zys0fIov3XT114+mQIpk=", "publicKeyB64": "tmp21VjPay+EhaMwmrFLfdjZo2KIjjT7VDqjmm27wHI=", "chainId": "bitgraph:main", "signatureB64": "LlqN1udFVXP9IFxsjwdF6//NMJZbm/IvBmlzDWJ7sfDAqCHD9fSH24w5AM4thFtf0YxMT/n5FedunYYwUQRgCA=="}, "agency": {"actor": {"keyId": "ee0c65174625e065c18e732a226b649a138625ba49c3d7dde026957082035cde", "publicKeyB64": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEVXEkwZppHxU13Ew9Ap+BQnxQcNXuMvH6KPepQe3t8t1Jh2/aEguB0Ttrzxw9WGxmB8a3AdVVv+ybchgrL8XIRg==", "algorithm": "ES256", "provider": "passkey"}, "authorization": {"purpose": "bitgraph/commit-authorize/v1", "format": "webauthn", "actorKeyId": "ee0c65174625e065c18e732a226b649a138625ba49c3d7dde026957082035cde", "artifactHash": "szEkIOHMuIaOXlqVG9uqKvaKtmnYmklfzOjEldzFP2E=", "challenge": "WzE2FoHLFBQhiwQCpdR8xXA0g1FfOcRCcTEG+1iOJa4=", "timestamp": 1787086799013, "authenticatorDataB64": "Gv0914qYXymsoynDxplniUKsvF16m3HSkeyxwvtTjnsdAAAAAA==", "clientDataJSON": "{\"type\":\"webauthn.get\",\"challenge\":\"WzE2FoHLFBQhiwQCpdR8xXA0g1FfOcRCcTEG-1iOJa4\",\"origin\":\"https://bitgraph.ing\",\"crossOrigin\":false}", "signatureB64": "MEUCIQDBAxBn+pAZcq9YTCVnGcoV6TX+dC1sR1R/0ufz5GSf8gIgMrlaLEPP8f4uFLfTXHT0EA+m85x1LcQNDYqf3557Ktk="}}, "proofHash": "gpbq9mzjkjy9xz7wZAsV+eLk1kwTeOtHogysF5rYS2w="}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "bitgraph-anchor-witness/1",
|
|
3
|
+
"headerRlpHex": "0xf90278a0b40e3a88ae7d5c107dd48503c73036a9ec382cf807c8ade7902389c161e93e77a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794dadb0d80178819f2319190d340ce9a924f783711a0421e753106383049bcf5c9fd339b3e40737ebfca4a41117bc26162bc2b542f7da0222fa1b22c0331e3c36cd9b7d11d5dd38e72106617f8eefcb7e1e34c58e87b64a0e1b785033a8cbc93c926e779d4a20e76b959cb4a507426258aec8223b32739d8b901007df77d335fcfbfbfffefefffbffbff7efb5bffefcdfb7ffbfff7bfffeebfefff9fffbefae4dfc3757dfffbff892fbfffffab77f7feefb9fffdfadffd16ff6febffffd2c75ffefffb5bff7f1b7dedffffc077f6fffb75dffaf1c7d2e5fff63f755f3ed120ffeefeffddfdefefbfbbfdffbe575efffdf7e5d33fff7fff2ffbf6ef83ff6bbbf7bf77fefbefe9faf737f7bfc7f5c5b7fdefffffed7bff5775f7ffeedf7777feefbf7f1e7f7fb5cfdc6bfddbff7edefefdddfd4ddfffff3bbfefe7ff7fedfd3fdfefeffffffffff9597ffe759ffff3dffffff7feddf7f7fa756f7cdacbffff77df7fdfaf2fff73f6d9df7deee5ff97b1fdfffdfefbdbfb7df79fffbf80840188b298840393870084020e1228846a7bd55b8a4275696c6465724e6574a003e75244081f38a3700ddbd87fd5c9ca45d2424c478ef199371134924a9462e588000000000000000084049120a8a0cc35135a513f4b5594eedd2ad8ee10e49ec602f209585b3c96776fb71ec9b0e7831e0000840aafde36a0cb0fbc3b6f4ec529821e2c0b3122ba994bf018f24b0286717010024229e1cc09a0e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
|
4
|
+
"blockNumber": 25735832,
|
|
5
|
+
"blockHash": "0xd20342041898e98ecaa7a07ce4d962561288755e23984e0114d154a5e75bd1a1"
|
|
6
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "bitgraph/1",
|
|
3
|
+
"artifact": {
|
|
4
|
+
"hashAlg": "sha256",
|
|
5
|
+
"digestB64": "ya3LF/xYXUsyLLaRa5atPA0w36iNe2sOEZtMFJzoCx8="
|
|
6
|
+
},
|
|
7
|
+
"commit": {
|
|
8
|
+
"nonceB64": "Z9NHxN5Vx7f3N8SRlk8Uah9RjD64Kbt9xedB83Mv3Ag=",
|
|
9
|
+
"counter": "1670",
|
|
10
|
+
"slotCounter": "1669",
|
|
11
|
+
"slotHashB64": "BcWtB3Ml8S3x9BujCeLH1b+c/VSdwyFViqeX0xDNOqg=",
|
|
12
|
+
"epochId": "kAx9jUikwWxf+alVyitZcqWPpYeRaDanlZFBVsm2q9s=",
|
|
13
|
+
"prevB64": "Khd8P6SVzr481lW63viAVAwwkXMrl5jX3uBeMjfFQZ8=",
|
|
14
|
+
"chainId": "bitgraph:main"
|
|
15
|
+
},
|
|
16
|
+
"signer": {
|
|
17
|
+
"publicKeyB64": "+EyavXXDJAvztDWhIh8Fu03WwMfUzYVgCXnp1lU18Ds=",
|
|
18
|
+
"signatureB64": "zVXdodzwzhm7fIsm7nz7CGuwHmeHAjA1gzCEN1G/QicFBZ6sprdedV2OVjHtedKZDxbQOSvVU60hSD2Dj6iaAQ=="
|
|
19
|
+
},
|
|
20
|
+
"environment": {
|
|
21
|
+
"enforcement": "measured-tee",
|
|
22
|
+
"measurement": "6483cedffed74680ffb287507744a398b288c3fb943eb3f2e4fe889f8b60b3d575ad8942350360b69a1bd7bf713df27f",
|
|
23
|
+
"attestation": {
|
|
24
|
+
"format": "aws-nitro",
|
|
25
|
+
"reportB64": "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"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"slotAllocation": {
|
|
29
|
+
"version": "bitgraph/slot/1",
|
|
30
|
+
"nonceB64": "Z9NHxN5Vx7f3N8SRlk8Uah9RjD64Kbt9xedB83Mv3Ag=",
|
|
31
|
+
"counter": "1669",
|
|
32
|
+
"epochId": "kAx9jUikwWxf+alVyitZcqWPpYeRaDanlZFBVsm2q9s=",
|
|
33
|
+
"publicKeyB64": "+EyavXXDJAvztDWhIh8Fu03WwMfUzYVgCXnp1lU18Ds=",
|
|
34
|
+
"chainId": "bitgraph:main",
|
|
35
|
+
"signatureB64": "sEx4coi4XxoaFCuUnOPDnvLa5uJfEuafAt44kmVpAQMbhJjwIXz5Hq2xeynIWgWdd91zYuHW+R/goDARTSLNAA=="
|
|
36
|
+
},
|
|
37
|
+
"attribution": {
|
|
38
|
+
"name": "Ethereum Anchor",
|
|
39
|
+
"title": "https://etherscan.io/block/25735832",
|
|
40
|
+
"message": "0xd20342041898e98ecaa7a07ce4d962561288755e23984e0114d154a5e75bd1a1"
|
|
41
|
+
},
|
|
42
|
+
"proofHash": "dWyW7MuTIAbQAHNoRyohc17A9GhGD1Cof9JqtAFUrF4="
|
|
43
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "bitgraph-anchor-witness/1",
|
|
3
|
+
"headerRlpHex": "0xf90286a02503d8262a3a5bd39a93f835f338a720434de7db353666a432d3af470ffc32e0a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347944838b106fce9647bdf1e7877bf73ce8b0bad5f97a0cf917d0242c222689c6ffec1e370ede05b474b64bf872cff3f1e77b207e84df0a0860c3a345b84903a1b2c6222e217424fd9ecc7df833db93ddd5534c82c35cb5ca0fbcccc621bc16881ca28d5be42348d32da5ec5614576be29f61f4413a6eea770b90100b9f73afff7fbdd71edef3fabfaf67dbf67f60f4bdfcf3aefeffd45fdfff8ed3f7dfe5f39b96f87b7cff6dbbf7cfe7395bf7ffefbfff3fffff7fbc7f7bbfe67c5fef6ffff4ffefbbd6e7f59bff3779eb9c7ff5f3fb2ff6c77befbff97ddefff86fcbcff55bffbfcd794f48fb3fcbeafc5faab4faf69ce77fe2bf0fbbf53ffde3b9d7776fff9feeb5bbbeff67eff17e7fff37bdab3ff8dc65fd5e76de5bbfcd53d7fef95777fd1af6fdd757bfebaf7fdce557ffff5e9be7e4b4fecbfbeb6f7ef73efafff8f67ebdf7712dbdff8057cffb53fcfffe37e69f1fa777bfbbaeb11fda6e676bd65b760bf9c5ff6d7fffefbdffdffedddff9ffb3d69b35ffa7c7ece7db780840188b29784039387008402077531846a7bd54398546974616e2028746974616e6275696c6465722e78797a29a0ec6cba377edad8dba8ff3c107a4a3df470239a0ae9d0fcdd11efddc52fb8358188000000000000000084047dc210a09f522911c579bcb780c77c3f3684c5478b64265ae99f6b11017b22d425343b3883060000840aadde36a0c3ab61e8d9a8e9935d60604b636336867145eebed5408f477aa1f239fa6a125ba0e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
|
4
|
+
"blockNumber": 25735831,
|
|
5
|
+
"blockHash": "0xb40e3a88ae7d5c107dd48503c73036a9ec382cf807c8ade7902389c161e93e77"
|
|
6
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "bitgraph/1",
|
|
3
|
+
"artifact": {
|
|
4
|
+
"hashAlg": "sha256",
|
|
5
|
+
"digestB64": "ki5C7mF2smUeovIXfsjaQWDpJlNeuh/RqojLVO9x1po="
|
|
6
|
+
},
|
|
7
|
+
"commit": {
|
|
8
|
+
"nonceB64": "Yy8vOkAYWfg49uKe6ageYcGqTZ1XQoqIlnn3i2cU6iI=",
|
|
9
|
+
"counter": "1428",
|
|
10
|
+
"slotCounter": "1427",
|
|
11
|
+
"slotHashB64": "CDiOgdW2+WfYRYFgC3Nq7nFGORlAna5rhumMPw0jIRI=",
|
|
12
|
+
"epochId": "kAx9jUikwWxf+alVyitZcqWPpYeRaDanlZFBVsm2q9s=",
|
|
13
|
+
"prevB64": "7l8DjZkNO//ouuiDP9SqlZ4zjX0coCOgnYfOOOAnsf4=",
|
|
14
|
+
"chainId": "bitgraph:main"
|
|
15
|
+
},
|
|
16
|
+
"signer": {
|
|
17
|
+
"publicKeyB64": "+EyavXXDJAvztDWhIh8Fu03WwMfUzYVgCXnp1lU18Ds=",
|
|
18
|
+
"signatureB64": "Qkx5qkbs9ftKA5RSYFjBZiSSpwoOaIzrTL7hHfvoo8DLMfnVoh+gSlJLKQzpqI5eTZ/nF62uXel3wlzyUY/iDA=="
|
|
19
|
+
},
|
|
20
|
+
"environment": {
|
|
21
|
+
"enforcement": "measured-tee",
|
|
22
|
+
"measurement": "6483cedffed74680ffb287507744a398b288c3fb943eb3f2e4fe889f8b60b3d575ad8942350360b69a1bd7bf713df27f",
|
|
23
|
+
"attestation": {
|
|
24
|
+
"format": "aws-nitro",
|
|
25
|
+
"reportB64": "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"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"slotAllocation": {
|
|
29
|
+
"version": "bitgraph/slot/1",
|
|
30
|
+
"nonceB64": "Yy8vOkAYWfg49uKe6ageYcGqTZ1XQoqIlnn3i2cU6iI=",
|
|
31
|
+
"counter": "1427",
|
|
32
|
+
"epochId": "kAx9jUikwWxf+alVyitZcqWPpYeRaDanlZFBVsm2q9s=",
|
|
33
|
+
"publicKeyB64": "+EyavXXDJAvztDWhIh8Fu03WwMfUzYVgCXnp1lU18Ds=",
|
|
34
|
+
"chainId": "bitgraph:main",
|
|
35
|
+
"signatureB64": "3O+/iIgdF4/9YImCVjT7keEmaJ/bu63x61l7GJvBFPVrqto5S2RDQKluhEvX8HjREvnZhXrTG2FU1aL2P4msDg=="
|
|
36
|
+
},
|
|
37
|
+
"attribution": {
|
|
38
|
+
"name": "Ethereum Anchor",
|
|
39
|
+
"title": "https://etherscan.io/block/25735831",
|
|
40
|
+
"message": "0xb40e3a88ae7d5c107dd48503c73036a9ec382cf807c8ade7902389c161e93e77"
|
|
41
|
+
},
|
|
42
|
+
"proofHash": "dkZTDDfmmrAxL1FWJwqJXBUH8AxCWUr6cLT7eA79Fhw=",
|
|
43
|
+
"ethereum": {
|
|
44
|
+
"blockNumber": 25735831,
|
|
45
|
+
"blockHash": "0xb40e3a88ae7d5c107dd48503c73036a9ec382cf807c8ade7902389c161e93e77"
|
|
46
|
+
}
|
|
47
|
+
}
|