@mikeargento/bitgraph-verify 1.3.0 → 1.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.
@@ -0,0 +1,235 @@
1
+ // Copyright (c) 2024-2026 Mike Argento. Licensed under the MIT License. See LICENSE.
2
+ /**
3
+ * BitGraph Fuse verification (spec 10): two paths, one comparison.
4
+ *
5
+ * Given a proof and a file:
6
+ * 1. Verify the proof as an ordinary bitgraph/1 proof. Fail: stop.
7
+ * 2. Hash the file.
8
+ * 3. Hash equals the artifact digest: RECORDED when nothing marks the proof
9
+ * fused; otherwise the file IS the fused bytes: recompute the commitment
10
+ * from the proof's own slot record, locate it in the bytes per the
11
+ * declared placement, compare.
12
+ * 4. Hash equals the origin digest: rebuild the fused bytes from this file,
13
+ * the proof's slot record and the placement; hash; compare with the
14
+ * artifact digest. A false origin cannot yield bytes that hash to the
15
+ * signed artifact digest, which is what makes an unsigned origin hint
16
+ * self-proving.
17
+ * 5. Neither: NO_MATCH. The proof proves nothing about this file.
18
+ *
19
+ * A Fuse failure is never reinterpreted as a valid recorded proof, and the
20
+ * categories are reported separately, never collapsed to one verdict. The
21
+ * wall-clock floor (the last anchored block preceding the slot) needs anchor
22
+ * evidence this package does not carry; the Player computes it. This module
23
+ * reports the causal span [N, M] and the bounded statements without it.
24
+ */
25
+ import { sha256 } from "@noble/hashes/sha256";
26
+ import { verifyProofIntegrity } from "./verifier.js";
27
+ import { bytesEqual, bytesToBase64, computeSlotCommitment, getPlacement, PLACEMENTS, mergeMarkers, parseFrame, readFrameMarker, readFuseAttribution, } from "./fuse.js";
28
+ export function spanOf(proof) {
29
+ const c = proof.commit;
30
+ if (typeof c.counter !== "string" || typeof c.slotCounter !== "string" || typeof c.epochId !== "string")
31
+ return null;
32
+ let positions;
33
+ try {
34
+ positions = (BigInt(c.counter) - BigInt(c.slotCounter)).toString();
35
+ }
36
+ catch {
37
+ return null;
38
+ }
39
+ return {
40
+ slotCounter: c.slotCounter,
41
+ commitCounter: c.counter,
42
+ epochId: c.epochId,
43
+ chainId: typeof c.chainId === "string" ? c.chainId : null,
44
+ positions,
45
+ };
46
+ }
47
+ /** The floor sentence every fused verdict ends with: bounded below by the slot, above by the commit. */
48
+ export function floorStatement(span) {
49
+ return `The exact fused bytes could not feasibly have been finalized before their signed slot allocation at position ${span.slotCounter}, and were committed no later than position ${span.commitCounter}.`;
50
+ }
51
+ function statements(category, span, originMatched) {
52
+ if (span === null)
53
+ return [];
54
+ const out = [];
55
+ // The origin sentence names exactly what was checked. On the origin path the
56
+ // supplied file was rebuilt into the committed artifact, so its existence by
57
+ // M is established. On the direct path only the fused bytes were supplied:
58
+ // an embedded origin digest agreeing with the signed marker is consistency,
59
+ // not a check of the original, and a check that did not run is never a verdict.
60
+ if (category === "FUSED_FROM_ORIGIN") {
61
+ out.push(`The supplied original rebuilds the committed fused artifact byte for byte, so these exact original bytes existed no later than commit position ${span.commitCounter}.`);
62
+ }
63
+ else if (category === "FUSED_DIRECT" && originMatched) {
64
+ out.push("The fused bytes carry an origin digest that matches the signed marker; the original itself was not supplied and was not checked.");
65
+ }
66
+ if (category === "FUSED_DIRECT" || category === "FUSED_FROM_ORIGIN") {
67
+ out.push(floorStatement(span));
68
+ }
69
+ if (category === "RECORDED") {
70
+ out.push(`These exact bytes existed no later than commit position ${span.commitCounter}.`);
71
+ }
72
+ return out;
73
+ }
74
+ export async function verifyFuse(opts) {
75
+ const { proof, bytes } = opts;
76
+ const frame = opts.frame === undefined || opts.frame === null ? null : (parseFrame(opts.frame) ?? null);
77
+ const fileDigest = sha256(bytes);
78
+ const fileDigestB64 = bytesToBase64(fileDigest);
79
+ const artifactDigestB64 = proof?.artifact?.digestB64 ?? "";
80
+ const base = (category, extra, reason) => ({
81
+ category,
82
+ proof: extra.proof ?? { valid: true },
83
+ marker: extra.marker ?? null,
84
+ placement: extra.placement ?? null,
85
+ fileDigestB64,
86
+ artifactDigestB64,
87
+ originDigestB64: extra.originDigestB64 ?? null,
88
+ slotCommitmentB64: extra.slotCommitmentB64 ?? null,
89
+ span: extra.span ?? null,
90
+ policy: extra.policy ?? { spanExceeded: false, maxPositions: null },
91
+ statements: extra.statements ?? [],
92
+ reason,
93
+ });
94
+ // 1. The underlying proof.
95
+ const integrity = await verifyProofIntegrity(opts.trustAnchors !== undefined ? { proof, trustAnchors: opts.trustAnchors } : { proof });
96
+ if (!integrity.valid) {
97
+ const reason = integrity.reason ?? "proof failed verification";
98
+ return base("INVALID_UNDERLYING_PROOF", { proof: { valid: false, reason } }, reason);
99
+ }
100
+ // The marker: the signed attribution is authoritative for what it declares;
101
+ // the advisory manifest fills in an undeclared placement or origin hint.
102
+ const marker = mergeMarkers(readFuseAttribution(proof), frame !== null ? readFrameMarker(frame) : null);
103
+ const originDigest = marker?.originDigest;
104
+ const originDigestB64 = originDigest !== undefined ? bytesToBase64(originDigest) : null;
105
+ const span = spanOf(proof);
106
+ // Optional span policy, computed once, reported separately from validity.
107
+ const maxPositions = opts.maxPositions === undefined ? null : BigInt(opts.maxPositions);
108
+ const policy = {
109
+ spanExceeded: maxPositions !== null && span !== null && BigInt(span.positions) > maxPositions,
110
+ maxPositions: maxPositions === null ? null : maxPositions.toString(),
111
+ };
112
+ const common = { proof: { valid: true }, marker, originDigestB64, span, policy };
113
+ // 3. The file is the committed bytes.
114
+ if (fileDigestB64 === artifactDigestB64) {
115
+ if (marker === null) {
116
+ return base("RECORDED", { ...common, statements: statements("RECORDED", span, false) }, null);
117
+ }
118
+ const slot = proof.slotAllocation;
119
+ if (slot === undefined) {
120
+ return base("INVALID_SLOT_COMMITMENT", common, "the proof carries no slot record, so no commitment can be recomputed");
121
+ }
122
+ let expected;
123
+ try {
124
+ expected = computeSlotCommitment(slot);
125
+ }
126
+ catch (err) {
127
+ return base("INVALID_SLOT_COMMITMENT", common, `commitment could not be recomputed: ${err instanceof Error ? err.message : String(err)}`);
128
+ }
129
+ const slotCommitmentB64 = bytesToBase64(expected);
130
+ let placement = marker.placement === null ? undefined : getPlacement(marker.placement);
131
+ let located = placement === undefined ? null : placement.locate(bytes);
132
+ if (marker.placement === null) {
133
+ // Undeclared: try the registry in its fixed order and report the one that matched.
134
+ for (const p of PLACEMENTS) {
135
+ const l = p.locate(bytes);
136
+ if (l !== null) {
137
+ placement = p;
138
+ located = l;
139
+ break;
140
+ }
141
+ }
142
+ if (placement === undefined) {
143
+ return base("INVALID_SLOT_COMMITMENT", { ...common, slotCommitmentB64 }, "no registered placement finds a commitment in the fused bytes");
144
+ }
145
+ }
146
+ else if (placement === undefined) {
147
+ return base("UNDETERMINED_PLACEMENT", { ...common, slotCommitmentB64 }, `placement "${marker.placement}" is not registered; the commitment cannot be located`);
148
+ }
149
+ if (located === null) {
150
+ return base("INVALID_SLOT_COMMITMENT", { ...common, slotCommitmentB64, placement: placement.id }, `no ${placement.id} commitment found in the fused bytes`);
151
+ }
152
+ if (!bytesEqual(located.commitment, expected)) {
153
+ return base("INVALID_SLOT_COMMITMENT", { ...common, slotCommitmentB64, placement: placement.id }, "the commitment in the fused bytes does not match the proof's slot record");
154
+ }
155
+ // Origin consistency: what the fused bytes say about the origin versus the marker.
156
+ let originMatched = false;
157
+ if (originDigest !== undefined) {
158
+ const embedded = located.originDigest ?? (located.originalBytes !== undefined ? sha256(located.originalBytes) : undefined);
159
+ if (embedded !== undefined) {
160
+ if (!bytesEqual(embedded, originDigest)) {
161
+ return base("INVALID_ORIGIN_ATTRIBUTION", { ...common, slotCommitmentB64, placement: placement.id }, marker.originSource === "attribution"
162
+ ? "the origin digest in the signed attribution does not match the origin inside the fused bytes"
163
+ : "the origin digest in the manifest does not match the origin inside the fused bytes");
164
+ }
165
+ originMatched = true;
166
+ }
167
+ }
168
+ return base("FUSED_DIRECT", { ...common, slotCommitmentB64, placement: placement.id, statements: statements("FUSED_DIRECT", span, originMatched) }, null);
169
+ }
170
+ // 4. The file is the original: rebuild the fused bytes.
171
+ if (originDigest !== undefined && bytesEqual(fileDigest, originDigest)) {
172
+ const slot = proof.slotAllocation;
173
+ if (slot === undefined) {
174
+ return base("INVALID_SLOT_COMMITMENT", common, "the proof carries no slot record, so the fused bytes cannot be rebuilt");
175
+ }
176
+ let commitment;
177
+ try {
178
+ commitment = computeSlotCommitment(slot);
179
+ }
180
+ catch (err) {
181
+ return base("INVALID_SLOT_COMMITMENT", common, `commitment could not be recomputed: ${err instanceof Error ? err.message : String(err)}`);
182
+ }
183
+ const slotCommitmentB64 = bytesToBase64(commitment);
184
+ const declared = marker !== null && marker.placement !== null ? getPlacement(marker.placement) : undefined;
185
+ if (marker !== null && marker.placement !== null && declared === undefined) {
186
+ return base("UNDETERMINED_PLACEMENT", { ...common, slotCommitmentB64 }, `placement "${marker.placement}" is not registered; the fused bytes cannot be rebuilt`);
187
+ }
188
+ const candidates = declared !== undefined ? [declared] : PLACEMENTS.filter((p) => p.byteExact);
189
+ const artifactDigest = proof.artifact.digestB64;
190
+ for (const p of candidates) {
191
+ if (!p.byteExact)
192
+ continue;
193
+ let rebuilt;
194
+ try {
195
+ rebuilt = p.build({ original: bytes, originDigest, commitment });
196
+ }
197
+ catch {
198
+ continue;
199
+ }
200
+ if (bytesToBase64(sha256(rebuilt)) === artifactDigest) {
201
+ return base("FUSED_FROM_ORIGIN", { ...common, slotCommitmentB64, placement: p.id, statements: statements("FUSED_FROM_ORIGIN", span, true) }, null);
202
+ }
203
+ }
204
+ return base("RECONSTRUCTION_MISMATCH", { ...common, slotCommitmentB64, placement: declared?.id ?? null }, declared !== undefined
205
+ ? `rebuilding ${declared.id} from this file and the proof's slot record does not reproduce the committed artifact digest`
206
+ : "no registered byte-exact placement rebuilds the committed artifact digest from this file");
207
+ }
208
+ // 5. Neither.
209
+ return base("NO_MATCH", common, "this file matches neither the committed artifact digest nor the origin digest; the proof proves nothing about it");
210
+ }
211
+ /**
212
+ * Strict ordering between two proofs where counters are comparable (same
213
+ * signer key, epoch, and chain): fused artifact B was assembled after
214
+ * artifact A was committed when commitCounter(A) < slotCounter(B). Returns
215
+ * null when the two are not comparable; an old pooled slot makes this false,
216
+ * never a false positive.
217
+ */
218
+ export function assembledAfterCommit(a, b) {
219
+ const chain = (p) => p.commit.chainId ?? null;
220
+ if (a.signer.publicKeyB64 !== b.signer.publicKeyB64)
221
+ return null;
222
+ if (a.commit.epochId === undefined || a.commit.epochId !== b.commit.epochId)
223
+ return null;
224
+ if (chain(a) !== chain(b))
225
+ return null;
226
+ if (typeof a.commit.counter !== "string" || typeof b.commit.slotCounter !== "string")
227
+ return null;
228
+ try {
229
+ return BigInt(a.commit.counter) < BigInt(b.commit.slotCounter);
230
+ }
231
+ catch {
232
+ return null;
233
+ }
234
+ }
235
+ //# sourceMappingURL=fuse-verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fuse-verify.js","sourceRoot":"","sources":["../src/fuse-verify.ts"],"names":[],"mappings":"AAAA,qFAAqF;AAErF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAErD,OAAO,EACL,UAAU,EACV,aAAa,EACb,qBAAqB,EACrB,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,UAAU,EACV,eAAe,EACf,mBAAmB,GAGpB,MAAM,WAAW,CAAC;AAqDnB,MAAM,UAAU,MAAM,CAAC,KAAoB;IACzC,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;IACvB,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,WAAW,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACrH,IAAI,SAAiB,CAAC;IACtB,IAAI,CAAC;QACH,SAAS,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IACrE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO;QACL,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,aAAa,EAAE,CAAC,CAAC,OAAO;QACxB,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,OAAO,EAAE,OAAQ,CAA2B,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAG,CAA0B,CAAC,OAAkB,CAAC,CAAC,CAAC,IAAI;QAC1H,SAAS;KACV,CAAC;AACJ,CAAC;AAED,wGAAwG;AACxG,MAAM,UAAU,cAAc,CAAC,IAAc;IAC3C,OAAO,gHAAgH,IAAI,CAAC,WAAW,+CAA+C,IAAI,CAAC,aAAa,GAAG,CAAC;AAC9M,CAAC;AAED,SAAS,UAAU,CAAC,QAAsB,EAAE,IAAqB,EAAE,aAAsB;IACvF,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,EAAE,CAAC;IAC7B,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,6EAA6E;IAC7E,6EAA6E;IAC7E,2EAA2E;IAC3E,4EAA4E;IAC5E,gFAAgF;IAChF,IAAI,QAAQ,KAAK,mBAAmB,EAAE,CAAC;QACrC,GAAG,CAAC,IAAI,CACN,kJAAkJ,IAAI,CAAC,aAAa,GAAG,CACxK,CAAC;IACJ,CAAC;SAAM,IAAI,QAAQ,KAAK,cAAc,IAAI,aAAa,EAAE,CAAC;QACxD,GAAG,CAAC,IAAI,CACN,kIAAkI,CACnI,CAAC;IACJ,CAAC;IACD,IAAI,QAAQ,KAAK,cAAc,IAAI,QAAQ,KAAK,mBAAmB,EAAE,CAAC;QACpE,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;IACjC,CAAC;IACD,IAAI,QAAQ,KAAK,UAAU,EAAE,CAAC;QAC5B,GAAG,CAAC,IAAI,CAAC,2DAA2D,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC;IAC7F,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAuB;IACtD,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;IAC9B,MAAM,KAAK,GAAqB,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC;IAC1H,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IACjC,MAAM,aAAa,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;IAChD,MAAM,iBAAiB,GAAG,KAAK,EAAE,QAAQ,EAAE,SAAS,IAAI,EAAE,CAAC;IAE3D,MAAM,IAAI,GAAG,CAAC,QAAsB,EAAE,KAAgC,EAAE,MAAqB,EAAoB,EAAE,CAAC,CAAC;QACnH,QAAQ;QACR,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE;QACrC,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,IAAI;QAC5B,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,IAAI;QAClC,aAAa;QACb,iBAAiB;QACjB,eAAe,EAAE,KAAK,CAAC,eAAe,IAAI,IAAI;QAC9C,iBAAiB,EAAE,KAAK,CAAC,iBAAiB,IAAI,IAAI;QAClD,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,IAAI;QACxB,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE;QACnE,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,EAAE;QAClC,MAAM;KACP,CAAC,CAAC;IAEH,2BAA2B;IAC3B,MAAM,SAAS,GAAG,MAAM,oBAAoB,CAC1C,IAAI,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CACzF,CAAC;IACF,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;QACrB,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,IAAI,2BAA2B,CAAC;QAC/D,OAAO,IAAI,CAAC,0BAA0B,EAAE,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;IACvF,CAAC;IAED,4EAA4E;IAC5E,yEAAyE;IACzE,MAAM,MAAM,GAAsB,YAAY,CAAC,mBAAmB,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC3H,MAAM,YAAY,GAAG,MAAM,EAAE,YAAY,CAAC;IAC1C,MAAM,eAAe,GAAG,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACxF,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAE3B,0EAA0E;IAC1E,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACxF,MAAM,MAAM,GAAG;QACb,YAAY,EAAE,YAAY,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,YAAY;QAC7F,YAAY,EAAE,YAAY,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,EAAE;KACrE,CAAC;IAEF,MAAM,MAAM,GAAG,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAEjF,sCAAsC;IACtC,IAAI,aAAa,KAAK,iBAAiB,EAAE,CAAC;QACxC,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,OAAO,IAAI,CAAC,UAAU,EAAE,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,UAAU,CAAC,UAAU,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAChG,CAAC;QACD,MAAM,IAAI,GAAG,KAAK,CAAC,cAAc,CAAC;QAClC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC,yBAAyB,EAAE,MAAM,EAAE,sEAAsE,CAAC,CAAC;QACzH,CAAC;QACD,IAAI,QAAoB,CAAC;QACzB,IAAI,CAAC;YACH,QAAQ,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;QACzC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,yBAAyB,EAAE,MAAM,EAAE,uCAAuC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5I,CAAC;QACD,MAAM,iBAAiB,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;QAClD,IAAI,SAAS,GAAG,MAAM,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACvF,IAAI,OAAO,GAAG,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,IAAI,MAAM,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;YAC9B,mFAAmF;YACnF,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;gBAC3B,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAC1B,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;oBAAC,SAAS,GAAG,CAAC,CAAC;oBAAC,OAAO,GAAG,CAAC,CAAC;oBAAC,MAAM;gBAAC,CAAC;YACxD,CAAC;YACD,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;gBAC5B,OAAO,IAAI,CAAC,yBAAyB,EAAE,EAAE,GAAG,MAAM,EAAE,iBAAiB,EAAE,EAAE,+DAA+D,CAAC,CAAC;YAC5I,CAAC;QACH,CAAC;aAAM,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YACnC,OAAO,IAAI,CAAC,wBAAwB,EAAE,EAAE,GAAG,MAAM,EAAE,iBAAiB,EAAE,EAAE,cAAc,MAAM,CAAC,SAAS,uDAAuD,CAAC,CAAC;QACjK,CAAC;QACD,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACrB,OAAO,IAAI,CAAC,yBAAyB,EAAE,EAAE,GAAG,MAAM,EAAE,iBAAiB,EAAE,SAAS,EAAE,SAAS,CAAC,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC,EAAE,sCAAsC,CAAC,CAAC;QAC9J,CAAC;QACD,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,EAAE,CAAC;YAC9C,OAAO,IAAI,CAAC,yBAAyB,EAAE,EAAE,GAAG,MAAM,EAAE,iBAAiB,EAAE,SAAS,EAAE,SAAS,CAAC,EAAE,EAAE,EAAE,0EAA0E,CAAC,CAAC;QAChL,CAAC;QACD,mFAAmF;QACnF,IAAI,aAAa,GAAG,KAAK,CAAC;QAC1B,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;YAC/B,MAAM,QAAQ,GAAG,OAAO,CAAC,YAAY,IAAI,CAAC,OAAO,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;YAC3H,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC3B,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,YAAY,CAAC,EAAE,CAAC;oBACxC,OAAO,IAAI,CACT,4BAA4B,EAC5B,EAAE,GAAG,MAAM,EAAE,iBAAiB,EAAE,SAAS,EAAE,SAAS,CAAC,EAAE,EAAE,EACzD,MAAM,CAAC,YAAY,KAAK,aAAa;wBACnC,CAAC,CAAC,8FAA8F;wBAChG,CAAC,CAAC,oFAAoF,CACzF,CAAC;gBACJ,CAAC;gBACD,aAAa,GAAG,IAAI,CAAC;YACvB,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC,cAAc,EAAE,EAAE,GAAG,MAAM,EAAE,iBAAiB,EAAE,SAAS,EAAE,SAAS,CAAC,EAAE,EAAE,UAAU,EAAE,UAAU,CAAC,cAAc,EAAE,IAAI,EAAE,aAAa,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAC5J,CAAC;IAED,wDAAwD;IACxD,IAAI,YAAY,KAAK,SAAS,IAAI,UAAU,CAAC,UAAU,EAAE,YAAY,CAAC,EAAE,CAAC;QACvE,MAAM,IAAI,GAAG,KAAK,CAAC,cAAc,CAAC;QAClC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC,yBAAyB,EAAE,MAAM,EAAE,wEAAwE,CAAC,CAAC;QAC3H,CAAC;QACD,IAAI,UAAsB,CAAC;QAC3B,IAAI,CAAC;YACH,UAAU,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;QAC3C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,yBAAyB,EAAE,MAAM,EAAE,uCAAuC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5I,CAAC;QACD,MAAM,iBAAiB,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;QACpD,MAAM,QAAQ,GAAG,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC3G,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,SAAS,KAAK,IAAI,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3E,OAAO,IAAI,CAAC,wBAAwB,EAAE,EAAE,GAAG,MAAM,EAAE,iBAAiB,EAAE,EAAE,cAAc,MAAM,CAAC,SAAS,wDAAwD,CAAC,CAAC;QAClK,CAAC;QACD,MAAM,UAAU,GAAG,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAC/F,MAAM,cAAc,GAAG,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC;QAChD,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;YAC3B,IAAI,CAAC,CAAC,CAAC,SAAS;gBAAE,SAAS;YAC3B,IAAI,OAAmB,CAAC;YACxB,IAAI,CAAC;gBACH,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC,CAAC;YACnE,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;YACD,IAAI,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,cAAc,EAAE,CAAC;gBACtD,OAAO,IAAI,CAAC,mBAAmB,EAAE,EAAE,GAAG,MAAM,EAAE,iBAAiB,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,UAAU,EAAE,UAAU,CAAC,mBAAmB,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;YACrJ,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CACT,yBAAyB,EACzB,EAAE,GAAG,MAAM,EAAE,iBAAiB,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,IAAI,IAAI,EAAE,EACjE,QAAQ,KAAK,SAAS;YACpB,CAAC,CAAC,cAAc,QAAQ,CAAC,EAAE,8FAA8F;YACzH,CAAC,CAAC,0FAA0F,CAC/F,CAAC;IACJ,CAAC;IAED,cAAc;IACd,OAAO,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,kHAAkH,CAAC,CAAC;AACtJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,CAAgB,EAAE,CAAgB;IACrE,MAAM,KAAK,GAAG,CAAC,CAAgB,EAAE,EAAE,CAAE,CAAC,CAAC,MAA+B,CAAC,OAAO,IAAI,IAAI,CAAC;IACvF,IAAI,CAAC,CAAC,MAAM,CAAC,YAAY,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY;QAAE,OAAO,IAAI,CAAC;IACjE,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IACzF,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,IAAI,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,MAAM,CAAC,WAAW,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAClG,IAAI,CAAC;QACH,OAAO,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IACjE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
package/dist/fuse.d.ts ADDED
@@ -0,0 +1,232 @@
1
+ import type { Attribution, BitGraphProof, SlotAllocation } from "./types.js";
2
+ export declare const FUSE_PROFILE: "bitgraph-fuse/1";
3
+ /** Domain separation prefix: the 15 profile bytes followed by one zero byte. */
4
+ export declare const FUSE_DOMAIN: Uint8Array;
5
+ /**
6
+ * The signed attribution name that marks a fused proof (spec 6.5): the profile
7
+ * id itself, the stable wire identifier of this construction. A product name
8
+ * may change; the v1 wire identifier does not (ruled 2026-09-03).
9
+ */
10
+ export declare const FUSE_ATTRIBUTION_NAME: "bitgraph-fuse/1";
11
+ /** Trailer placement: 8 ASCII magic bytes, 8 reserved zero bytes, 32 commitment bytes. */
12
+ export declare const TRAILER_MAGIC: "BGFUSE01";
13
+ export declare const TRAILER_LENGTH = 48;
14
+ /** Fixed paths inside a container/1 archive. */
15
+ export declare const CONTAINER_MANIFEST_PATH: "bitgraph-fuse/manifest.json";
16
+ export declare const CONTAINER_ORIGINAL_PATH: "bitgraph-fuse/original";
17
+ export declare function bytesToBase64(bytes: Uint8Array): string;
18
+ /** Strict standard base64 (RFC 4648 section 4): no whitespace, no URL-safe alphabet, correct padding. */
19
+ export declare function base64ToBytes(b64: string): Uint8Array | null;
20
+ export declare function bytesToHex(bytes: Uint8Array): string;
21
+ /** Lowercase hex only; uppercase is rejected so one digest has one spelling. */
22
+ export declare function hexToBytes(hex: string): Uint8Array | null;
23
+ export declare function bytesEqual(a: Uint8Array, b: Uint8Array): boolean;
24
+ /**
25
+ * The enclave's canonical slot body: the signed subset of the slot record,
26
+ * excluding signatureB64, with `time` and `chainId` present only when the
27
+ * record carries them. Identical to the reconstruction in verifier.ts
28
+ * (verifySlotAllocation) and to the enclave's own slotBody. There is exactly
29
+ * one serialization of a slot record; this is it.
30
+ */
31
+ export declare function canonicalSlotBody(slot: SlotAllocation): Record<string, unknown>;
32
+ /** SHA-256 of the canonical slot body; equals the proof's commit.slotHashB64. */
33
+ export declare function computeSlotRecordHash(slot: SlotAllocation): Uint8Array;
34
+ /** The exact preimage of the commitment, for vectors and audits: domain || slotRecordHash || nonce. */
35
+ export declare function slotCommitmentPreimage(slot: SlotAllocation): Uint8Array;
36
+ /** slotCommitment = SHA256(domain || slotRecordHash || nonce). */
37
+ export declare function computeSlotCommitment(slot: SlotAllocation): Uint8Array;
38
+ export interface FusePayload {
39
+ type: typeof FUSE_PROFILE;
40
+ origin?: {
41
+ algorithm: "sha256";
42
+ digest: string;
43
+ };
44
+ slotCommitment: {
45
+ algorithm: "sha256";
46
+ digest: string;
47
+ };
48
+ }
49
+ /** Build the canonical Form C payload bytes (spec 6.2). Digests are lowercase hex. */
50
+ export declare function buildFusePayload(commitment: Uint8Array, originDigest?: Uint8Array): Uint8Array;
51
+ /**
52
+ * Strict parse of Form C bytes. The bytes must be valid UTF-8 JSON, a plain
53
+ * object with exactly the allowed keys, the profile type, lowercase-hex
54
+ * 32-byte digests, and must equal their own re-canonicalization byte for byte
55
+ * (which rejects whitespace, key-order games, and duplicate keys, since a
56
+ * duplicate cannot survive a round trip). Returns null on any deviation.
57
+ */
58
+ export declare function parseFusePayload(bytes: Uint8Array): {
59
+ commitment: Uint8Array;
60
+ originDigest?: Uint8Array;
61
+ } | null;
62
+ export type PlacementId = "trailer/1" | "container/1" | "produced/1" | "set/1";
63
+ export interface Located {
64
+ /** The commitment found in the fused bytes. */
65
+ commitment: Uint8Array;
66
+ /** The origin digest written into the fused bytes, when the placement writes one. */
67
+ originDigest?: Uint8Array;
68
+ /** The original's bytes as carried inside the fused bytes, for placements that carry them. */
69
+ originalBytes?: Uint8Array;
70
+ }
71
+ export interface Placement {
72
+ readonly id: PlacementId;
73
+ /** A: in-file placement of an existing original; B: container; C: produced artifact. */
74
+ readonly form: "A" | "B" | "C";
75
+ /** True when the fused bytes are a deterministic function of (original, proof, placement). */
76
+ readonly byteExact: boolean;
77
+ /** Build the fused bytes. Forms A and B require `original`; Form C forbids it. */
78
+ build(input: {
79
+ original?: Uint8Array;
80
+ originDigest?: Uint8Array;
81
+ commitment: Uint8Array;
82
+ }): Uint8Array;
83
+ /** Find the commitment in fused bytes, or null when the marker is absent or malformed. */
84
+ locate(fused: Uint8Array): Located | null;
85
+ }
86
+ /** Registered placements in the fixed order a verifier tries them when none is declared. */
87
+ export declare const PLACEMENTS: readonly Placement[];
88
+ export declare const SET_PLACEMENT_ID: "set/1";
89
+ /**
90
+ * The proof.metadata key under which a set proof carries its manifest as a
91
+ * parsed plain object: the profile id itself, namespaced so it cannot collide
92
+ * with a site's own metadata keys. metadata is UNSIGNED and advisory. The
93
+ * manifest is protected only because its canonical bytes must hash to the
94
+ * signed artifact digest, which verifyFuseMember checks before reading a row.
95
+ */
96
+ export declare const SET_METADATA_KEY: "bitgraph-fuse/1";
97
+ /** One member of a set, bytes view: the build input and the parse output. */
98
+ export interface SetMember {
99
+ /** SHA-256 of the member's FUSED bytes. */
100
+ artifact: Uint8Array;
101
+ /** SHA-256 of the member's ORIGINAL bytes; selects the rebuild path and feeds lookup by original. */
102
+ origin: Uint8Array;
103
+ /** The placement that carries the commitment inside this member's fused bytes. */
104
+ placement: string;
105
+ }
106
+ /** The manifest as JSON: the type of the value under proof.metadata[SET_METADATA_KEY]. */
107
+ export interface SetManifest {
108
+ members: Array<{
109
+ artifact: {
110
+ algorithm: "sha256";
111
+ digest: string;
112
+ };
113
+ origin: {
114
+ algorithm: "sha256";
115
+ digest: string;
116
+ };
117
+ placement: string;
118
+ }>;
119
+ placement: typeof SET_PLACEMENT_ID;
120
+ slotCommitment: {
121
+ algorithm: "sha256";
122
+ digest: string;
123
+ };
124
+ type: typeof FUSE_PROFILE;
125
+ }
126
+ /**
127
+ * Build the canonical set manifest bytes. Rows are sorted strictly ascending
128
+ * by artifact digest (byte order, which is the lexicographic order of the
129
+ * lowercase hex), so the same members in any input order give the same bytes.
130
+ * Throws on a commitment or digest that is not 32 bytes, an empty list, a
131
+ * malformed placement id, a member placement of "set/1" (no nesting in v1),
132
+ * or a duplicate artifact digest. Duplicate ORIGIN digests are permitted: one
133
+ * original fused two ways is two members with two artifact digests.
134
+ */
135
+ export declare function buildSetManifest(commitment: Uint8Array, members: readonly SetMember[]): Uint8Array;
136
+ /**
137
+ * Strict parse of set manifest bytes, in the style of parseFusePayload. The
138
+ * bytes must be valid UTF-8 JSON, a plain object with exactly the keys
139
+ * {members, placement, slotCommitment, type}, the profile type, placement
140
+ * "set/1", a lowercase-hex 32-byte commitment, at least one row, every row
141
+ * exactly {artifact, origin, placement} with 32-byte digests and a
142
+ * well-formed placement id other than "set/1", and finally must equal
143
+ * buildSetManifest over what was read byte for byte. That one comparison
144
+ * rejects whitespace, key reordering, duplicate JSON keys (a duplicate cannot
145
+ * survive a round trip), unsorted or duplicated rows, non-canonical escapes
146
+ * and trailing bytes. Registration of a row's placement is NOT checked here:
147
+ * a v2 placement must not poison v1 readers, and it surfaces per row as
148
+ * UNDETERMINED_PLACEMENT at verify time. Returns null on any deviation.
149
+ */
150
+ export declare function parseSetManifest(bytes: Uint8Array): {
151
+ commitment: Uint8Array;
152
+ members: SetMember[];
153
+ } | null;
154
+ /**
155
+ * The manifest bytes a proof carries under proof.metadata[SET_METADATA_KEY],
156
+ * re-canonicalized from the parsed object, or null when there is none or it
157
+ * is not a plain object. UNBOUND and UNVALIDATED: metadata is unsigned, so
158
+ * this returns bytes only, never rows. Nothing reads a member from it except
159
+ * through verifyFuseMember, which first requires these bytes to parse
160
+ * strictly and to hash to the signed artifact digest.
161
+ */
162
+ export declare function readSetMetadata(proof: BitGraphProof): Uint8Array | null;
163
+ /**
164
+ * Resolve a placement by id. set/1 resolves here but is NOT in PLACEMENTS:
165
+ * the undeclared scan is for bytes whose placement was not declared, whereas
166
+ * a set manifest is identified by hashing to the signed artifact digest and
167
+ * by its signed title, so the scan order of every existing fixture is
168
+ * literally unchanged.
169
+ */
170
+ export declare function getPlacement(id: string): Placement | undefined;
171
+ /**
172
+ * attribution.name = "bitgraph-fuse/1" (the profile id), title = placement id,
173
+ * message = origin digest in standard base64. A set has no single origin, so
174
+ * set/1 refuses an origin digest: a set/1 marker carrying one is out of
175
+ * profile and verifyFuseMember refuses it.
176
+ */
177
+ export declare function fuseAttribution(placement: PlacementId, originDigest?: Uint8Array): Attribution;
178
+ export type MarkerSource = "attribution" | "manifest";
179
+ /**
180
+ * What marks a proof as fused, and where each fact came from. The signed
181
+ * attribution is authoritative for what it declares; a Frame's advisory
182
+ * manifest may fill in what the signature leaves undeclared (an origin hint,
183
+ * a placement), and is made self-proving only by reconstruction.
184
+ */
185
+ export interface FuseMarker {
186
+ /** The placement id, or null when none is declared (a verifier then tries the registry in order). */
187
+ placement: string | null;
188
+ placementSource: MarkerSource | null;
189
+ originDigest?: Uint8Array;
190
+ originSource?: MarkerSource;
191
+ /** "attribution" when the proof's signed attribution marks it fused, else "manifest". */
192
+ source: MarkerSource;
193
+ }
194
+ /** Read the fused marker from a proof's signed attribution, or null when the proof is not marked fused. */
195
+ export declare function readFuseAttribution(proof: BitGraphProof): FuseMarker | null;
196
+ /** Merge the signed marker with a manifest marker: the signature wins wherever it declares. */
197
+ export declare function mergeMarkers(signed: FuseMarker | null, manifest: FuseMarker | null): FuseMarker | null;
198
+ export interface FuseFrame {
199
+ type: typeof FUSE_PROFILE;
200
+ manifest: {
201
+ /** Empty string when the placement is left undeclared. */
202
+ placement: string;
203
+ origin?: {
204
+ algorithm: "sha256";
205
+ digest: string;
206
+ };
207
+ artifact: {
208
+ algorithm: "sha256";
209
+ digest: string;
210
+ };
211
+ fusedFile: string | null;
212
+ };
213
+ fusePayload?: FusePayload;
214
+ proof: BitGraphProof;
215
+ }
216
+ export declare function buildFrame(input: {
217
+ proof: BitGraphProof;
218
+ placement: PlacementId;
219
+ artifactDigest: Uint8Array;
220
+ originDigest?: Uint8Array;
221
+ fusedFile: string | null;
222
+ fusePayload?: Uint8Array;
223
+ }): FuseFrame;
224
+ /**
225
+ * Structural read of a Frame. The manifest is advisory: nothing here is
226
+ * trusted beyond its shape, and the nested proof is returned exactly as
227
+ * found for the ordinary verifier. Null when this is not a Frame.
228
+ */
229
+ export declare function parseFrame(input: unknown): FuseFrame | null;
230
+ /** Marker from a Frame's advisory manifest (unsigned; made self-proving only by reconstruction). */
231
+ export declare function readFrameMarker(frame: FuseFrame): FuseMarker;
232
+ //# sourceMappingURL=fuse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fuse.d.ts","sourceRoot":"","sources":["../src/fuse.ts"],"names":[],"mappings":"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"}