@mikeargento/bitgraph 1.9.1 → 1.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.
Files changed (248) hide show
  1. package/README.md +21 -21
  2. package/dist/fuse-cli.js +2 -2
  3. package/dist/fuse-cli.js.map +1 -1
  4. package/dist/fuse.d.ts +15 -1
  5. package/dist/fuse.d.ts.map +1 -1
  6. package/dist/fuse.js +29 -12
  7. package/dist/fuse.js.map +1 -1
  8. package/package.json +12 -8
  9. package/src/fuse-cli.ts +2 -2
  10. package/src/fuse.ts +46 -13
  11. package/dist/__tests__/audit-anchors.test.d.ts +0 -2
  12. package/dist/__tests__/audit-anchors.test.d.ts.map +0 -1
  13. package/dist/__tests__/audit-anchors.test.js +0 -152
  14. package/dist/__tests__/audit-anchors.test.js.map +0 -1
  15. package/dist/__tests__/audit-anomalies.test.d.ts +0 -2
  16. package/dist/__tests__/audit-anomalies.test.d.ts.map +0 -1
  17. package/dist/__tests__/audit-anomalies.test.js +0 -663
  18. package/dist/__tests__/audit-anomalies.test.js.map +0 -1
  19. package/dist/__tests__/audit-attestation.test.d.ts +0 -2
  20. package/dist/__tests__/audit-attestation.test.d.ts.map +0 -1
  21. package/dist/__tests__/audit-attestation.test.js +0 -403
  22. package/dist/__tests__/audit-attestation.test.js.map +0 -1
  23. package/dist/__tests__/audit-bench-smoke.test.d.ts +0 -2
  24. package/dist/__tests__/audit-bench-smoke.test.d.ts.map +0 -1
  25. package/dist/__tests__/audit-bench-smoke.test.js +0 -87
  26. package/dist/__tests__/audit-bench-smoke.test.js.map +0 -1
  27. package/dist/__tests__/audit-boundary.test.d.ts +0 -20
  28. package/dist/__tests__/audit-boundary.test.d.ts.map +0 -1
  29. package/dist/__tests__/audit-boundary.test.js +0 -84
  30. package/dist/__tests__/audit-boundary.test.js.map +0 -1
  31. package/dist/__tests__/audit-cli.test.d.ts +0 -2
  32. package/dist/__tests__/audit-cli.test.d.ts.map +0 -1
  33. package/dist/__tests__/audit-cli.test.js +0 -239
  34. package/dist/__tests__/audit-cli.test.js.map +0 -1
  35. package/dist/__tests__/audit-dependencies.test.d.ts +0 -2
  36. package/dist/__tests__/audit-dependencies.test.d.ts.map +0 -1
  37. package/dist/__tests__/audit-dependencies.test.js +0 -116
  38. package/dist/__tests__/audit-dependencies.test.js.map +0 -1
  39. package/dist/__tests__/audit-fixtures.d.ts +0 -265
  40. package/dist/__tests__/audit-fixtures.d.ts.map +0 -1
  41. package/dist/__tests__/audit-fixtures.js +0 -511
  42. package/dist/__tests__/audit-fixtures.js.map +0 -1
  43. package/dist/__tests__/audit-ingest.test.d.ts +0 -2
  44. package/dist/__tests__/audit-ingest.test.d.ts.map +0 -1
  45. package/dist/__tests__/audit-ingest.test.js +0 -473
  46. package/dist/__tests__/audit-ingest.test.js.map +0 -1
  47. package/dist/__tests__/audit-memory-ingest.test.d.ts +0 -12
  48. package/dist/__tests__/audit-memory-ingest.test.d.ts.map +0 -1
  49. package/dist/__tests__/audit-memory-ingest.test.js +0 -135
  50. package/dist/__tests__/audit-memory-ingest.test.js.map +0 -1
  51. package/dist/__tests__/audit-property.test.d.ts +0 -2
  52. package/dist/__tests__/audit-property.test.d.ts.map +0 -1
  53. package/dist/__tests__/audit-property.test.js +0 -771
  54. package/dist/__tests__/audit-property.test.js.map +0 -1
  55. package/dist/__tests__/audit-real-fixtures.test.d.ts +0 -2
  56. package/dist/__tests__/audit-real-fixtures.test.d.ts.map +0 -1
  57. package/dist/__tests__/audit-real-fixtures.test.js +0 -132
  58. package/dist/__tests__/audit-real-fixtures.test.js.map +0 -1
  59. package/dist/__tests__/audit-real-live.test.d.ts +0 -2
  60. package/dist/__tests__/audit-real-live.test.d.ts.map +0 -1
  61. package/dist/__tests__/audit-real-live.test.js +0 -107
  62. package/dist/__tests__/audit-real-live.test.js.map +0 -1
  63. package/dist/__tests__/audit-reconstruct.test.d.ts +0 -2
  64. package/dist/__tests__/audit-reconstruct.test.d.ts.map +0 -1
  65. package/dist/__tests__/audit-reconstruct.test.js +0 -287
  66. package/dist/__tests__/audit-reconstruct.test.js.map +0 -1
  67. package/dist/__tests__/audit-report.test.d.ts +0 -2
  68. package/dist/__tests__/audit-report.test.d.ts.map +0 -1
  69. package/dist/__tests__/audit-report.test.js +0 -186
  70. package/dist/__tests__/audit-report.test.js.map +0 -1
  71. package/dist/__tests__/audit-roundtrip.test.d.ts +0 -2
  72. package/dist/__tests__/audit-roundtrip.test.d.ts.map +0 -1
  73. package/dist/__tests__/audit-roundtrip.test.js +0 -368
  74. package/dist/__tests__/audit-roundtrip.test.js.map +0 -1
  75. package/dist/__tests__/audit-temporal.test.d.ts +0 -2
  76. package/dist/__tests__/audit-temporal.test.d.ts.map +0 -1
  77. package/dist/__tests__/audit-temporal.test.js +0 -364
  78. package/dist/__tests__/audit-temporal.test.js.map +0 -1
  79. package/dist/__tests__/audit-tiers.test.d.ts +0 -2
  80. package/dist/__tests__/audit-tiers.test.d.ts.map +0 -1
  81. package/dist/__tests__/audit-tiers.test.js +0 -282
  82. package/dist/__tests__/audit-tiers.test.js.map +0 -1
  83. package/dist/__tests__/audit-witness-real.test.d.ts +0 -19
  84. package/dist/__tests__/audit-witness-real.test.d.ts.map +0 -1
  85. package/dist/__tests__/audit-witness-real.test.js +0 -82
  86. package/dist/__tests__/audit-witness-real.test.js.map +0 -1
  87. package/dist/__tests__/audit-witness.test.d.ts +0 -2
  88. package/dist/__tests__/audit-witness.test.d.ts.map +0 -1
  89. package/dist/__tests__/audit-witness.test.js +0 -308
  90. package/dist/__tests__/audit-witness.test.js.map +0 -1
  91. package/dist/__tests__/canonical.test.d.ts +0 -2
  92. package/dist/__tests__/canonical.test.d.ts.map +0 -1
  93. package/dist/__tests__/canonical.test.js +0 -162
  94. package/dist/__tests__/canonical.test.js.map +0 -1
  95. package/dist/__tests__/chain-hash-anchor.test.d.ts +0 -22
  96. package/dist/__tests__/chain-hash-anchor.test.d.ts.map +0 -1
  97. package/dist/__tests__/chain-hash-anchor.test.js +0 -55
  98. package/dist/__tests__/chain-hash-anchor.test.js.map +0 -1
  99. package/dist/__tests__/commit-service.integration.test.d.ts +0 -2
  100. package/dist/__tests__/commit-service.integration.test.d.ts.map +0 -1
  101. package/dist/__tests__/commit-service.integration.test.js +0 -95
  102. package/dist/__tests__/commit-service.integration.test.js.map +0 -1
  103. package/dist/__tests__/constructor.test.d.ts +0 -2
  104. package/dist/__tests__/constructor.test.d.ts.map +0 -1
  105. package/dist/__tests__/constructor.test.js +0 -267
  106. package/dist/__tests__/constructor.test.js.map +0 -1
  107. package/dist/__tests__/declared-proof-fixture.d.ts +0 -66
  108. package/dist/__tests__/declared-proof-fixture.d.ts.map +0 -1
  109. package/dist/__tests__/declared-proof-fixture.js +0 -66
  110. package/dist/__tests__/declared-proof-fixture.js.map +0 -1
  111. package/dist/__tests__/fuse-inline.test.d.ts +0 -2
  112. package/dist/__tests__/fuse-inline.test.d.ts.map +0 -1
  113. package/dist/__tests__/fuse-inline.test.js +0 -181
  114. package/dist/__tests__/fuse-inline.test.js.map +0 -1
  115. package/dist/__tests__/fuse-placement.test.d.ts +0 -2
  116. package/dist/__tests__/fuse-placement.test.d.ts.map +0 -1
  117. package/dist/__tests__/fuse-placement.test.js +0 -31
  118. package/dist/__tests__/fuse-placement.test.js.map +0 -1
  119. package/dist/__tests__/fuse-roundtrip.test.d.ts +0 -2
  120. package/dist/__tests__/fuse-roundtrip.test.d.ts.map +0 -1
  121. package/dist/__tests__/fuse-roundtrip.test.js +0 -241
  122. package/dist/__tests__/fuse-roundtrip.test.js.map +0 -1
  123. package/dist/__tests__/fuse-sdk.test.d.ts +0 -2
  124. package/dist/__tests__/fuse-sdk.test.d.ts.map +0 -1
  125. package/dist/__tests__/fuse-sdk.test.js +0 -117
  126. package/dist/__tests__/fuse-sdk.test.js.map +0 -1
  127. package/dist/__tests__/fuse-set-sdk.test.d.ts +0 -2
  128. package/dist/__tests__/fuse-set-sdk.test.d.ts.map +0 -1
  129. package/dist/__tests__/fuse-set-sdk.test.js +0 -721
  130. package/dist/__tests__/fuse-set-sdk.test.js.map +0 -1
  131. package/dist/__tests__/fuse-set.test.d.ts +0 -2
  132. package/dist/__tests__/fuse-set.test.d.ts.map +0 -1
  133. package/dist/__tests__/fuse-set.test.js +0 -889
  134. package/dist/__tests__/fuse-set.test.js.map +0 -1
  135. package/dist/__tests__/fuse-set2.test.d.ts +0 -2
  136. package/dist/__tests__/fuse-set2.test.d.ts.map +0 -1
  137. package/dist/__tests__/fuse-set2.test.js +0 -294
  138. package/dist/__tests__/fuse-set2.test.js.map +0 -1
  139. package/dist/__tests__/fuse-vectors.test.d.ts +0 -2
  140. package/dist/__tests__/fuse-vectors.test.d.ts.map +0 -1
  141. package/dist/__tests__/fuse-vectors.test.js +0 -175
  142. package/dist/__tests__/fuse-vectors.test.js.map +0 -1
  143. package/dist/__tests__/fuse-verify.test.d.ts +0 -2
  144. package/dist/__tests__/fuse-verify.test.d.ts.map +0 -1
  145. package/dist/__tests__/fuse-verify.test.js +0 -250
  146. package/dist/__tests__/fuse-verify.test.js.map +0 -1
  147. package/dist/__tests__/hello-world.test.d.ts +0 -2
  148. package/dist/__tests__/hello-world.test.d.ts.map +0 -1
  149. package/dist/__tests__/hello-world.test.js +0 -9
  150. package/dist/__tests__/hello-world.test.js.map +0 -1
  151. package/dist/__tests__/mock-proof-fixture.d.ts +0 -15
  152. package/dist/__tests__/mock-proof-fixture.d.ts.map +0 -1
  153. package/dist/__tests__/mock-proof-fixture.js +0 -34
  154. package/dist/__tests__/mock-proof-fixture.js.map +0 -1
  155. package/dist/__tests__/policy-enforcement.test.d.ts +0 -2
  156. package/dist/__tests__/policy-enforcement.test.d.ts.map +0 -1
  157. package/dist/__tests__/policy-enforcement.test.js +0 -188
  158. package/dist/__tests__/policy-enforcement.test.js.map +0 -1
  159. package/dist/__tests__/proof-hash-regression.test.d.ts +0 -2
  160. package/dist/__tests__/proof-hash-regression.test.d.ts.map +0 -1
  161. package/dist/__tests__/proof-hash-regression.test.js +0 -95
  162. package/dist/__tests__/proof-hash-regression.test.js.map +0 -1
  163. package/dist/__tests__/proof-hash.test.d.ts +0 -2
  164. package/dist/__tests__/proof-hash.test.d.ts.map +0 -1
  165. package/dist/__tests__/proof-hash.test.js +0 -116
  166. package/dist/__tests__/proof-hash.test.js.map +0 -1
  167. package/dist/__tests__/proof-integrity.test.d.ts +0 -2
  168. package/dist/__tests__/proof-integrity.test.d.ts.map +0 -1
  169. package/dist/__tests__/proof-integrity.test.js +0 -454
  170. package/dist/__tests__/proof-integrity.test.js.map +0 -1
  171. package/dist/__tests__/realistic-proof-fixture.d.ts +0 -56
  172. package/dist/__tests__/realistic-proof-fixture.d.ts.map +0 -1
  173. package/dist/__tests__/realistic-proof-fixture.js +0 -57
  174. package/dist/__tests__/realistic-proof-fixture.js.map +0 -1
  175. package/dist/__tests__/run.test.d.ts +0 -2
  176. package/dist/__tests__/run.test.d.ts.map +0 -1
  177. package/dist/__tests__/run.test.js +0 -178
  178. package/dist/__tests__/run.test.js.map +0 -1
  179. package/dist/__tests__/verifier.test.d.ts +0 -2
  180. package/dist/__tests__/verifier.test.d.ts.map +0 -1
  181. package/dist/__tests__/verifier.test.js +0 -531
  182. package/dist/__tests__/verifier.test.js.map +0 -1
  183. package/dist/canonical.d.ts +0 -54
  184. package/dist/canonical.d.ts.map +0 -1
  185. package/dist/canonical.js +0 -119
  186. package/dist/canonical.js.map +0 -1
  187. package/dist/proof-hash.d.ts +0 -9
  188. package/dist/proof-hash.d.ts.map +0 -1
  189. package/dist/proof-hash.js +0 -75
  190. package/dist/proof-hash.js.map +0 -1
  191. package/dist/types.d.ts +0 -705
  192. package/dist/types.d.ts.map +0 -1
  193. package/dist/types.js +0 -3
  194. package/dist/types.js.map +0 -1
  195. package/dist/verifier.d.ts +0 -27
  196. package/dist/verifier.d.ts.map +0 -1
  197. package/dist/verifier.js +0 -844
  198. package/dist/verifier.js.map +0 -1
  199. package/src/__tests__/audit-anchors.test.ts +0 -188
  200. package/src/__tests__/audit-anomalies.test.ts +0 -815
  201. package/src/__tests__/audit-attestation.test.ts +0 -529
  202. package/src/__tests__/audit-bench-smoke.test.ts +0 -108
  203. package/src/__tests__/audit-boundary.test.ts +0 -96
  204. package/src/__tests__/audit-cli.test.ts +0 -288
  205. package/src/__tests__/audit-dependencies.test.ts +0 -141
  206. package/src/__tests__/audit-fixtures.ts +0 -736
  207. package/src/__tests__/audit-ingest.test.ts +0 -575
  208. package/src/__tests__/audit-memory-ingest.test.ts +0 -156
  209. package/src/__tests__/audit-property.test.ts +0 -892
  210. package/src/__tests__/audit-real-fixtures.test.ts +0 -153
  211. package/src/__tests__/audit-real-live.test.ts +0 -128
  212. package/src/__tests__/audit-reconstruct.test.ts +0 -353
  213. package/src/__tests__/audit-report.test.ts +0 -222
  214. package/src/__tests__/audit-roundtrip.test.ts +0 -464
  215. package/src/__tests__/audit-temporal.test.ts +0 -446
  216. package/src/__tests__/audit-tiers.test.ts +0 -343
  217. package/src/__tests__/audit-witness-real.test.ts +0 -92
  218. package/src/__tests__/audit-witness.test.ts +0 -345
  219. package/src/__tests__/canonical.test.ts +0 -253
  220. package/src/__tests__/chain-hash-anchor.test.ts +0 -67
  221. package/src/__tests__/commit-service.integration.test.ts +0 -117
  222. package/src/__tests__/constructor.test.ts +0 -340
  223. package/src/__tests__/declared-proof-fixture.ts +0 -65
  224. package/src/__tests__/fuse-inline.test.ts +0 -211
  225. package/src/__tests__/fuse-placement.test.ts +0 -32
  226. package/src/__tests__/fuse-roundtrip.test.ts +0 -243
  227. package/src/__tests__/fuse-sdk.test.ts +0 -142
  228. package/src/__tests__/fuse-set-sdk.test.ts +0 -852
  229. package/src/__tests__/fuse-set.test.ts +0 -1027
  230. package/src/__tests__/fuse-set2.test.ts +0 -343
  231. package/src/__tests__/fuse-vectors.test.ts +0 -218
  232. package/src/__tests__/fuse-verify.test.ts +0 -278
  233. package/src/__tests__/hello-world.test.ts +0 -10
  234. package/src/__tests__/mock-proof-fixture.ts +0 -36
  235. package/src/__tests__/policy-enforcement.test.ts +0 -226
  236. package/src/__tests__/proof-hash-regression.test.ts +0 -107
  237. package/src/__tests__/proof-hash.test.ts +0 -129
  238. package/src/__tests__/proof-integrity.test.ts +0 -576
  239. package/src/__tests__/real-fixtures/anchor-after-112762.json +0 -47
  240. package/src/__tests__/real-fixtures/anchor-with-ethereum-112758.json +0 -47
  241. package/src/__tests__/real-fixtures/live-proof-0.json +0 -42
  242. package/src/__tests__/real-fixtures/live-proof-1.json +0 -43
  243. package/src/__tests__/real-fixtures/live-proof-2.json +0 -43
  244. package/src/__tests__/real-fixtures/successor-112760.json +0 -38
  245. package/src/__tests__/real-fixtures/witness-25525146.json +0 -6
  246. package/src/__tests__/real-fixtures/witness-25525147.json +0 -6
  247. package/src/__tests__/realistic-proof-fixture.ts +0 -57
  248. package/src/__tests__/verifier.test.ts +0 -624
@@ -1,576 +0,0 @@
1
- // Copyright (c) Argento Computing Inc. All rights reserved. See LICENSE.
2
-
3
- /**
4
- * Tests for verifyProofIntegrity, the bytes-free proof integrity API in
5
- * @mikeargento/bitgraph-verify.
6
- *
7
- * Also carries regression coverage asserting that verify() behavior is
8
- * unchanged by the shared-pipeline refactor: same checks, same order,
9
- * same failure strings.
10
- */
11
-
12
- import { describe, test, before, beforeEach } from "node:test";
13
- import * as assert from "node:assert/strict";
14
- import { getPublicKeyAsync, signAsync } from "@noble/ed25519";
15
- import { sha256 } from "@noble/hashes/sha256";
16
- import {
17
- verify,
18
- verifyProofIntegrity,
19
- resetEpochLinkState,
20
- createVerificationContext,
21
- canonicalize,
22
- } from "@mikeargento/bitgraph-verify";
23
- import type { BitGraphProof, ProofIntegrityResult } from "@mikeargento/bitgraph-verify";
24
- import { Constructor } from "../constructor.js";
25
- import type { HostCapabilities } from "../host.js";
26
-
27
- // ---------------------------------------------------------------------------
28
- // Test-fixture helpers
29
- // ---------------------------------------------------------------------------
30
-
31
- interface Fixture {
32
- proof: BitGraphProof;
33
- bytes: Uint8Array;
34
- publicKeyB64: string;
35
- measurement: string;
36
- }
37
-
38
- /** Constructor-built fixture, mirroring makeFixture in verifier.test.ts. */
39
- async function makeFixture(opts?: {
40
- epochId?: string;
41
- withCounter?: boolean;
42
- }): Promise<Fixture> {
43
- const privateKey = crypto.getRandomValues(new Uint8Array(32));
44
- const publicKeyBytes = await getPublicKeyAsync(privateKey);
45
- const publicKeyB64 = Buffer.from(publicKeyBytes).toString("base64");
46
- const measurement = "test-measurement-integrity";
47
-
48
- let counter = 0;
49
- const host: HostCapabilities = opts?.withCounter
50
- ? {
51
- enforcementTier: "stub" as const,
52
- getMeasurement: async () => measurement,
53
- getFreshNonce: async () => crypto.getRandomValues(new Uint8Array(16)),
54
- sign: async (data: Uint8Array) => signAsync(data, privateKey),
55
- getPublicKey: async () => publicKeyBytes,
56
- nextCounter: async () => String(++counter),
57
- }
58
- : {
59
- enforcementTier: "stub" as const,
60
- getMeasurement: async () => measurement,
61
- getFreshNonce: async () => crypto.getRandomValues(new Uint8Array(16)),
62
- sign: async (data: Uint8Array) => signAsync(data, privateKey),
63
- getPublicKey: async () => publicKeyBytes,
64
- };
65
-
66
- const ctor = await Constructor.initialize(
67
- opts?.epochId !== undefined ? { host, epochId: opts.epochId } : { host },
68
- );
69
-
70
- const bytes = new TextEncoder().encode("bitgraph-integrity-test-payload");
71
- const proof = await ctor.commit({ bytes });
72
-
73
- return { proof, bytes, publicKeyB64, measurement };
74
- }
75
-
76
- /** Deep-clone a proof so mutations don't affect the original. */
77
- function clone(proof: BitGraphProof): BitGraphProof {
78
- return JSON.parse(JSON.stringify(proof)) as BitGraphProof;
79
- }
80
-
81
- function b64(bytes: Uint8Array): string {
82
- return Buffer.from(bytes).toString("base64");
83
- }
84
-
85
- interface ManualKey {
86
- privateKey: Uint8Array;
87
- publicKeyB64: string;
88
- }
89
-
90
- async function makeKey(): Promise<ManualKey> {
91
- const privateKey = crypto.getRandomValues(new Uint8Array(32));
92
- const publicKeyB64 = b64(await getPublicKeyAsync(privateKey));
93
- return { privateKey, publicKeyB64 };
94
- }
95
-
96
- /**
97
- * Manually build and sign a proof over the exact canonical SignedBody
98
- * layout the verifier reconstructs. Used for slot-carrying and
99
- * epochLink-carrying proofs, which the root Constructor does not produce.
100
- */
101
- async function signBody(
102
- key: ManualKey,
103
- artifact: BitGraphProof["artifact"],
104
- commit: BitGraphProof["commit"],
105
- measurement: string,
106
- ): Promise<BitGraphProof> {
107
- const signedBody = {
108
- version: "bitgraph/1" as const,
109
- artifact,
110
- commit,
111
- publicKeyB64: key.publicKeyB64,
112
- enforcement: "stub" as const,
113
- measurement,
114
- };
115
- const signatureB64 = b64(await signAsync(canonicalize(signedBody), key.privateKey));
116
- return {
117
- version: "bitgraph/1",
118
- artifact,
119
- commit,
120
- signer: { publicKeyB64: key.publicKeyB64, signatureB64 },
121
- environment: { enforcement: "stub", measurement },
122
- };
123
- }
124
-
125
- interface SlotFixture {
126
- proof: BitGraphProof;
127
- bytes: Uint8Array;
128
- measurement: string;
129
- }
130
-
131
- /**
132
- * Build a slot-carrying proof: slot allocated at counter 1, commit at
133
- * counter 2, slotHashB64 binding the signed commit to the exact slot body.
134
- */
135
- async function makeSlotFixture(opts?: { commitCounter?: string }): Promise<SlotFixture> {
136
- const key = await makeKey();
137
- const measurement = "test-measurement-slot";
138
- const epochId = "epoch-slot-test";
139
- const nonceB64 = b64(crypto.getRandomValues(new Uint8Array(16)));
140
-
141
- const slotBody = {
142
- version: "bitgraph/slot/1" as const,
143
- nonceB64,
144
- counter: "1",
145
- time: 1_700_000_000_000,
146
- epochId,
147
- publicKeyB64: key.publicKeyB64,
148
- };
149
- const slotCanonical = canonicalize(slotBody);
150
- const slotSignatureB64 = b64(await signAsync(slotCanonical, key.privateKey));
151
- const slotHashB64 = b64(sha256(slotCanonical));
152
-
153
- const bytes = new TextEncoder().encode("bitgraph-integrity-slot-payload");
154
- const artifact: BitGraphProof["artifact"] = {
155
- hashAlg: "sha256",
156
- digestB64: b64(sha256(bytes)),
157
- };
158
- const commit: BitGraphProof["commit"] = {
159
- nonceB64,
160
- counter: opts?.commitCounter ?? "2",
161
- epochId,
162
- slotCounter: "1",
163
- slotHashB64,
164
- };
165
-
166
- const proof = await signBody(key, artifact, commit, measurement);
167
- proof.slotAllocation = { ...slotBody, signatureB64: slotSignatureB64 };
168
- return { proof, bytes, measurement };
169
- }
170
-
171
- interface EpochLinkFixture {
172
- proof: BitGraphProof;
173
- bytes: Uint8Array;
174
- }
175
-
176
- /**
177
- * Build an epoch-genesis proof carrying an epochLink. The link is inside
178
- * the signed commit, so the Ed25519 signature covers it.
179
- */
180
- async function makeEpochLinkFixture(opts?: {
181
- toEpochId?: string;
182
- samePrevKey?: boolean;
183
- }): Promise<EpochLinkFixture> {
184
- const key = await makeKey();
185
- const prevKey = await makeKey();
186
- const toEpochId = opts?.toEpochId ?? "epoch-successor-a";
187
-
188
- const epochLink = {
189
- prevEpochId: "epoch-predecessor-a",
190
- prevPublicKeyB64: opts?.samePrevKey === true ? key.publicKeyB64 : prevKey.publicKeyB64,
191
- prevCounter: "42",
192
- prevProofHashB64: b64(sha256(new TextEncoder().encode("predecessor-terminal-proof"))),
193
- toEpochId,
194
- toPublicKeyB64: key.publicKeyB64,
195
- };
196
-
197
- const bytes = new TextEncoder().encode("bitgraph-integrity-epochlink-payload");
198
- const artifact: BitGraphProof["artifact"] = {
199
- hashAlg: "sha256",
200
- digestB64: b64(sha256(bytes)),
201
- };
202
- const commit: BitGraphProof["commit"] = {
203
- nonceB64: b64(crypto.getRandomValues(new Uint8Array(16))),
204
- counter: "1",
205
- epochId: toEpochId,
206
- epochLink,
207
- };
208
-
209
- const proof = await signBody(key, artifact, commit, "test-measurement-epochlink");
210
- return { proof, bytes };
211
- }
212
-
213
- // ---------------------------------------------------------------------------
214
- // Module-level fixtures
215
- // ---------------------------------------------------------------------------
216
-
217
- let fx!: Fixture;
218
-
219
- before(async () => {
220
- fx = await makeFixture();
221
- });
222
-
223
- // ---------------------------------------------------------------------------
224
- // Happy path: integrity without bytes
225
- // ---------------------------------------------------------------------------
226
-
227
- describe("verifyProofIntegrity: valid proof, no bytes", () => {
228
- test("passes for a freshly created proof and reports binding not checked", async () => {
229
- const result = await verifyProofIntegrity({ proof: fx.proof });
230
- assert.deepEqual(result, { valid: true, artifactBinding: "not-checked" });
231
- });
232
-
233
- test("passes for a proof with counter and epochId", async () => {
234
- const chained = await makeFixture({ withCounter: true, epochId: "epoch-integrity-xyz" });
235
- const result = await verifyProofIntegrity({ proof: chained.proof });
236
- assert.deepEqual(result, { valid: true, artifactBinding: "not-checked" });
237
- });
238
-
239
- test("passes even when verify() with wrong bytes fails: binding is genuinely not checked", async () => {
240
- const wrongBytes = new Uint8Array([1, 2, 3]);
241
- const full = await verify({ proof: fx.proof, bytes: wrongBytes });
242
- assert.equal(full.valid, false);
243
- assert.match(full.reason ?? "", /digest mismatch/);
244
-
245
- const integrity = await verifyProofIntegrity({ proof: fx.proof });
246
- assert.deepEqual(integrity, { valid: true, artifactBinding: "not-checked" });
247
- });
248
- });
249
-
250
- // ---------------------------------------------------------------------------
251
- // Result shape
252
- // ---------------------------------------------------------------------------
253
-
254
- describe("verifyProofIntegrity: result shape", () => {
255
- test("failure result also carries artifactBinding 'not-checked' plus a reason", async () => {
256
- const tampered = clone(fx.proof);
257
- tampered.signer.signatureB64 = Buffer.alloc(64).toString("base64");
258
- const result: ProofIntegrityResult = await verifyProofIntegrity({ proof: tampered });
259
- assert.equal(result.valid, false);
260
- assert.equal(result.artifactBinding, "not-checked");
261
- assert.equal(typeof result.reason, "string");
262
- });
263
- });
264
-
265
- // ---------------------------------------------------------------------------
266
- // Tampering
267
- // ---------------------------------------------------------------------------
268
-
269
- describe("verifyProofIntegrity: tampering", () => {
270
- test("fails when signatureB64 is replaced with all-zeros", async () => {
271
- const tampered = clone(fx.proof);
272
- tampered.signer.signatureB64 = Buffer.alloc(64).toString("base64");
273
- const result = await verifyProofIntegrity({ proof: tampered });
274
- assert.equal(result.valid, false);
275
- assert.match(result.reason ?? "", /signature/);
276
- });
277
-
278
- test("fails when version is tampered, with a version reason", async () => {
279
- const tampered = clone(fx.proof);
280
- (tampered as unknown as Record<string, unknown>)["version"] = "bitgraph/2";
281
- const result = await verifyProofIntegrity({ proof: tampered });
282
- assert.equal(result.valid, false);
283
- assert.equal(result.reason, "unsupported proof version: bitgraph/2");
284
- });
285
-
286
- test("fails when a signed field (measurement) is tampered", async () => {
287
- const tampered = clone(fx.proof);
288
- tampered.environment.measurement = "evil-measurement";
289
- const result = await verifyProofIntegrity({ proof: tampered });
290
- assert.equal(result.valid, false);
291
- assert.match(result.reason ?? "", /signature/);
292
- });
293
-
294
- test("fails when artifact.digestB64 is not valid base64 (well-formedness still checked)", async () => {
295
- const tampered = clone(fx.proof);
296
- tampered.artifact.digestB64 = "!!!";
297
- const result = await verifyProofIntegrity({ proof: tampered });
298
- assert.equal(result.valid, false);
299
- assert.equal(result.reason, "artifact.digestB64 is not valid base64");
300
- });
301
-
302
- test("fails for non-object proof", async () => {
303
- const result = await verifyProofIntegrity({
304
- proof: "not-a-proof" as unknown as BitGraphProof,
305
- });
306
- assert.equal(result.valid, false);
307
- assert.match(result.reason ?? "", /object/);
308
- });
309
- });
310
-
311
- // ---------------------------------------------------------------------------
312
- // Slot allocation (bytes-free)
313
- // ---------------------------------------------------------------------------
314
-
315
- describe("verifyProofIntegrity: slot allocation", () => {
316
- test("passes for a valid slot-carrying proof", async () => {
317
- const slotFx = await makeSlotFixture();
318
- const result = await verifyProofIntegrity({ proof: slotFx.proof });
319
- assert.deepEqual(result, { valid: true, artifactBinding: "not-checked" });
320
- });
321
-
322
- test("fails when commit.slotHashB64 is tampered (signed field)", async () => {
323
- const slotFx = await makeSlotFixture();
324
- const tampered = clone(slotFx.proof);
325
- tampered.commit.slotHashB64 = Buffer.alloc(32, 0xee).toString("base64");
326
- const result = await verifyProofIntegrity({ proof: tampered });
327
- assert.equal(result.valid, false);
328
- assert.match(result.reason ?? "", /signature/);
329
- });
330
-
331
- test("fails with a slot binding reason when the embedded slot record is swapped", async () => {
332
- const slotA = await makeSlotFixture();
333
- const slotB = await makeSlotFixture();
334
- const tampered = clone(slotA.proof);
335
- // slotB's record is validly signed by its own key, but it is not the
336
- // record that slotA's signed commit.slotHashB64 binds to.
337
- tampered.slotAllocation = clone(slotB.proof).slotAllocation!;
338
- const result = await verifyProofIntegrity({ proof: tampered });
339
- assert.equal(result.valid, false);
340
- assert.match(result.reason ?? "", /slotHashB64 does not match SHA-256 of canonical slot body/);
341
- });
342
-
343
- test("fails when slotAllocation.counter is tampered (slot signature breaks)", async () => {
344
- const slotFx = await makeSlotFixture();
345
- const tampered = clone(slotFx.proof);
346
- tampered.slotAllocation!.counter = "999";
347
- const result = await verifyProofIntegrity({ proof: tampered });
348
- assert.equal(result.valid, false);
349
- assert.match(result.reason ?? "", /slotAllocation signature verification failed/);
350
- });
351
-
352
- test("fails when slot counter is not less than commit counter", async () => {
353
- // Slot at counter 1, commit also at counter 1: ordering violated even
354
- // though every signature is genuine.
355
- const slotFx = await makeSlotFixture({ commitCounter: "1" });
356
- const result = await verifyProofIntegrity({ proof: slotFx.proof });
357
- assert.equal(result.valid, false);
358
- assert.match(result.reason ?? "", /must be less than commit\.counter/);
359
- });
360
- });
361
-
362
- // ---------------------------------------------------------------------------
363
- // Epoch link (bytes-free)
364
- // ---------------------------------------------------------------------------
365
-
366
- describe("verifyProofIntegrity: epochLink", () => {
367
- beforeEach(() => {
368
- resetEpochLinkState();
369
- });
370
-
371
- test("passes for a valid epoch-genesis proof with epochLink", async () => {
372
- const linkFx = await makeEpochLinkFixture();
373
- const result = await verifyProofIntegrity({ proof: linkFx.proof });
374
- assert.deepEqual(result, { valid: true, artifactBinding: "not-checked" });
375
- });
376
-
377
- test("is idempotent for the same successor epoch", async () => {
378
- const linkFx = await makeEpochLinkFixture();
379
- const first = await verifyProofIntegrity({ proof: linkFx.proof });
380
- const second = await verifyProofIntegrity({ proof: linkFx.proof });
381
- assert.equal(first.valid, true);
382
- assert.equal(second.valid, true);
383
- });
384
-
385
- test("fails when predecessor and successor keys are identical", async () => {
386
- const linkFx = await makeEpochLinkFixture({ samePrevKey: true });
387
- const result = await verifyProofIntegrity({ proof: linkFx.proof });
388
- assert.equal(result.valid, false);
389
- assert.match(result.reason ?? "", /different keys/);
390
- });
391
-
392
- /* A rejected proof must not change what the verifier accepts afterwards.
393
- Before 2026-09-20 the single-successor map was written during the epoch
394
- link check, which runs BEFORE the policy check, so a proof refused for an
395
- untrusted measurement still claimed its predecessor and the next honest
396
- proof was reported as a fork. Verification is a function of its inputs. */
397
- test("a proof rejected by policy does not consume its predecessor", async () => {
398
- const rejected = await makeEpochLinkFixture({ toEpochId: "epoch-successor-a" });
399
- const honest = await makeEpochLinkFixture({ toEpochId: "epoch-successor-b" });
400
-
401
- const r1 = await verifyProofIntegrity({
402
- proof: rejected.proof,
403
- trustAnchors: { allowedMeasurements: ["some-other-measurement"] },
404
- });
405
- assert.equal(r1.valid, false);
406
-
407
- const r2 = await verifyProofIntegrity({ proof: honest.proof });
408
- assert.equal(r2.valid, true, r2.valid ? "" : r2.reason);
409
- });
410
-
411
- test("an explicit context keeps one verification's history out of another's", async () => {
412
- const a = await makeEpochLinkFixture({ toEpochId: "epoch-successor-a" });
413
- const b = await makeEpochLinkFixture({ toEpochId: "epoch-successor-b" });
414
- const one = createVerificationContext();
415
- const two = createVerificationContext();
416
-
417
- assert.equal((await verifyProofIntegrity({ proof: a.proof, context: one })).valid, true);
418
- assert.equal((await verifyProofIntegrity({ proof: b.proof, context: two })).valid, true);
419
-
420
- // The same context still catches the fork.
421
- const forked = await verifyProofIntegrity({ proof: b.proof, context: one });
422
- assert.equal(forked.valid, false);
423
- assert.match(forked.reason ?? "", /FORK DETECTED/);
424
- });
425
-
426
- test("detects a fork: same predecessor consumed by two successor epochs", async () => {
427
- const first = await makeEpochLinkFixture({ toEpochId: "epoch-successor-a" });
428
- const second = await makeEpochLinkFixture({ toEpochId: "epoch-successor-b" });
429
-
430
- const r1 = await verifyProofIntegrity({ proof: first.proof });
431
- assert.equal(r1.valid, true);
432
-
433
- const r2 = await verifyProofIntegrity({ proof: second.proof });
434
- assert.equal(r2.valid, false);
435
- assert.match(r2.reason ?? "", /FORK DETECTED/);
436
- });
437
- });
438
-
439
- // ---------------------------------------------------------------------------
440
- // Policy checks (trustAnchors)
441
- // ---------------------------------------------------------------------------
442
-
443
- describe("verifyProofIntegrity: policy (trustAnchors)", () => {
444
- test("passes when measurement is in the allowlist", async () => {
445
- const result = await verifyProofIntegrity({
446
- proof: fx.proof,
447
- trustAnchors: { allowedMeasurements: [fx.measurement] },
448
- });
449
- assert.deepEqual(result, { valid: true, artifactBinding: "not-checked" });
450
- });
451
-
452
- test("fails when measurement is not in the allowlist", async () => {
453
- const result = await verifyProofIntegrity({
454
- proof: fx.proof,
455
- trustAnchors: { allowedMeasurements: ["expected-meas"] },
456
- });
457
- assert.equal(result.valid, false);
458
- assert.match(result.reason ?? "", /measurement/);
459
- });
460
-
461
- test("fails when requireEnforcement does not match", async () => {
462
- const result = await verifyProofIntegrity({
463
- proof: fx.proof,
464
- trustAnchors: { requireEnforcement: "measured-tee" },
465
- });
466
- assert.equal(result.valid, false);
467
- assert.match(result.reason ?? "", /enforcement/);
468
- });
469
-
470
- test("requireSlot fails for a slotless proof and passes for a slot-carrying proof", async () => {
471
- const slotless = await verifyProofIntegrity({
472
- proof: fx.proof,
473
- trustAnchors: { requireSlot: true },
474
- });
475
- assert.equal(slotless.valid, false);
476
- assert.match(slotless.reason ?? "", /slotAllocation/);
477
-
478
- const slotFx = await makeSlotFixture();
479
- const slotted = await verifyProofIntegrity({
480
- proof: slotFx.proof,
481
- trustAnchors: { requireSlot: true },
482
- });
483
- assert.deepEqual(slotted, { valid: true, artifactBinding: "not-checked" });
484
- });
485
-
486
- test("counter policy applies without bytes", async () => {
487
- const slotFx = await makeSlotFixture();
488
- const pass = await verifyProofIntegrity({
489
- proof: slotFx.proof,
490
- trustAnchors: { minCounter: "1" },
491
- });
492
- assert.equal(pass.valid, true);
493
-
494
- const failResult = await verifyProofIntegrity({
495
- proof: slotFx.proof,
496
- trustAnchors: { minCounter: "999" },
497
- });
498
- assert.equal(failResult.valid, false);
499
- assert.match(failResult.reason ?? "", /counter/);
500
- });
501
- });
502
-
503
- // ---------------------------------------------------------------------------
504
- // Regression: verify() behavior unchanged by the shared-pipeline refactor
505
- // ---------------------------------------------------------------------------
506
-
507
- describe("regression: verify() unchanged", () => {
508
- test("valid proof with bytes returns exactly { valid: true }", async () => {
509
- const result = await verify({ proof: fx.proof, bytes: fx.bytes });
510
- assert.deepEqual(result, { valid: true });
511
- });
512
-
513
- test("wrong bytes fail with the exact digest mismatch reason", async () => {
514
- const result = await verify({ proof: fx.proof, bytes: new Uint8Array([9, 9, 9]) });
515
- assert.equal(result.valid, false);
516
- assert.equal(
517
- result.reason,
518
- "artifact digest mismatch: the provided bytes do not match the committed digest",
519
- );
520
- });
521
-
522
- test("tampered signature fails with the exact signature reason", async () => {
523
- const tampered = clone(fx.proof);
524
- tampered.signer.signatureB64 = Buffer.alloc(64).toString("base64");
525
- const result = await verify({ proof: tampered, bytes: fx.bytes });
526
- assert.equal(result.valid, false);
527
- assert.equal(result.reason, "signature verification failed: signature does not match");
528
- });
529
-
530
- test("tampered version fails with the exact version reason", async () => {
531
- const tampered = clone(fx.proof);
532
- (tampered as unknown as Record<string, unknown>)["version"] = "bitgraph/2";
533
- const result = await verify({ proof: tampered, bytes: fx.bytes });
534
- assert.equal(result.valid, false);
535
- assert.equal(result.reason, "unsupported proof version: bitgraph/2");
536
- });
537
-
538
- test("verify() and verifyProofIntegrity() agree on every non-artifact failure", async () => {
539
- const variants: Array<(p: BitGraphProof) => void> = [
540
- (p) => {
541
- (p as unknown as Record<string, unknown>)["version"] = "occ/1";
542
- },
543
- (p) => {
544
- p.signer.signatureB64 = Buffer.alloc(64).toString("base64");
545
- },
546
- (p) => {
547
- p.environment.measurement = "evil-measurement";
548
- },
549
- (p) => {
550
- delete (p as unknown as Record<string, unknown>)["signer"];
551
- },
552
- ];
553
-
554
- for (const mutate of variants) {
555
- const tampered = clone(fx.proof);
556
- mutate(tampered);
557
- const full = await verify({ proof: tampered, bytes: fx.bytes });
558
- const integrity = await verifyProofIntegrity({ proof: tampered });
559
- assert.equal(full.valid, integrity.valid);
560
- assert.equal(full.reason, integrity.reason);
561
- }
562
- });
563
-
564
- test("verify() accepts the slot-carrying fixture with its bytes", async () => {
565
- const slotFx = await makeSlotFixture();
566
- const result = await verify({ proof: slotFx.proof, bytes: slotFx.bytes });
567
- assert.deepEqual(result, { valid: true });
568
- });
569
-
570
- test("verify() accepts the epochLink fixture with its bytes", async () => {
571
- resetEpochLinkState();
572
- const linkFx = await makeEpochLinkFixture();
573
- const result = await verify({ proof: linkFx.proof, bytes: linkFx.bytes });
574
- assert.deepEqual(result, { valid: true });
575
- });
576
- });
@@ -1,47 +0,0 @@
1
- {
2
- "version": "bitgraph/1",
3
- "artifact": {
4
- "hashAlg": "sha256",
5
- "digestB64": "s0SCQLL8QR9pf1U/ep6prd3gF1qXAW6bZVf1S15KbfI="
6
- },
7
- "commit": {
8
- "nonceB64": "/fDc/tHc5VXw1lN6TbdloXwJ9kViJ2Xm6DPqAV4J/m8=",
9
- "counter": "112762",
10
- "slotCounter": "112761",
11
- "slotHashB64": "r2DHz1TJRWnW74PeyxhBKBAFc2yIJBE5AEeQIpEU1vs=",
12
- "epochId": "PlvP2VDcMH9RiBA3shEOrd8xEhHuJj6Gshym/V/qKNg=",
13
- "prevB64": "ZJs0jf97XakAdw1e7fiK3yMKpliUplgw6HgTw50n+bw=",
14
- "chainId": "bitgraph:main"
15
- },
16
- "signer": {
17
- "publicKeyB64": "yiKzaYXZyI+tHiSb7K/+OQv8XwErhez2TTk1efl6XAA=",
18
- "signatureB64": "PhE6MG8SyxFMJIGBSkWPftfs/qZ68liHoJ30i0gv0vHRm86sSrmGyEpxYYcY2gfmYRK+p5BLyOoCXc6bhoXCCA=="
19
- },
20
- "environment": {
21
- "enforcement": "measured-tee",
22
- "measurement": "e2fccbae77ee40aac4830e84f195e05d69eb4547bbd961f4d3459feba10807140424aca42ad03810354982598c86b9cb",
23
- "attestation": {
24
- "format": "aws-nitro",
25
- "reportB64": "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"
26
- }
27
- },
28
- "slotAllocation": {
29
- "version": "bitgraph/slot/1",
30
- "nonceB64": "/fDc/tHc5VXw1lN6TbdloXwJ9kViJ2Xm6DPqAV4J/m8=",
31
- "counter": "112761",
32
- "epochId": "PlvP2VDcMH9RiBA3shEOrd8xEhHuJj6Gshym/V/qKNg=",
33
- "publicKeyB64": "yiKzaYXZyI+tHiSb7K/+OQv8XwErhez2TTk1efl6XAA=",
34
- "chainId": "bitgraph:main",
35
- "signatureB64": "ywygI3mZcy7FR4JhTk7Sdk3MYrLdhXB3dUpv+VoTmpwdgQCBKXnTlzXCjsEv3/RXNmh0gzwnHgUAXrqF+lofDQ=="
36
- },
37
- "attribution": {
38
- "name": "Ethereum Anchor",
39
- "title": "https://etherscan.io/block/25525147",
40
- "message": "0x04f48a70f24f21daae546d1ae49132df9e767ba4238b92ae39f0c153eb1436dc"
41
- },
42
- "proofHash": "H7OZf8C1Ry7cbiFMg6wxfbiqBgWNYpzJDhMePmkmda4=",
43
- "ethereum": {
44
- "blockNumber": 25525147,
45
- "blockHash": "0x04f48a70f24f21daae546d1ae49132df9e767ba4238b92ae39f0c153eb1436dc"
46
- }
47
- }