@fluxpointstudios/orynq-sdk-midnight-prover 0.1.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 (82) hide show
  1. package/LICENSE +21 -0
  2. package/dist/index.d.ts +78 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +89 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/linking/cardano-anchor-link.d.ts +250 -0
  7. package/dist/linking/cardano-anchor-link.d.ts.map +1 -0
  8. package/dist/linking/cardano-anchor-link.js +447 -0
  9. package/dist/linking/cardano-anchor-link.js.map +1 -0
  10. package/dist/linking/index.d.ts +33 -0
  11. package/dist/linking/index.d.ts.map +1 -0
  12. package/dist/linking/index.js +31 -0
  13. package/dist/linking/index.js.map +1 -0
  14. package/dist/linking/proof-publication.d.ts +217 -0
  15. package/dist/linking/proof-publication.d.ts.map +1 -0
  16. package/dist/linking/proof-publication.js +385 -0
  17. package/dist/linking/proof-publication.js.map +1 -0
  18. package/dist/midnight/index.d.ts +30 -0
  19. package/dist/midnight/index.d.ts.map +1 -0
  20. package/dist/midnight/index.js +27 -0
  21. package/dist/midnight/index.js.map +1 -0
  22. package/dist/midnight/proof-server-client.d.ts +236 -0
  23. package/dist/midnight/proof-server-client.d.ts.map +1 -0
  24. package/dist/midnight/proof-server-client.js +422 -0
  25. package/dist/midnight/proof-server-client.js.map +1 -0
  26. package/dist/midnight/public-inputs.d.ts +134 -0
  27. package/dist/midnight/public-inputs.d.ts.map +1 -0
  28. package/dist/midnight/public-inputs.js +338 -0
  29. package/dist/midnight/public-inputs.js.map +1 -0
  30. package/dist/midnight/witness-builder.d.ts +119 -0
  31. package/dist/midnight/witness-builder.d.ts.map +1 -0
  32. package/dist/midnight/witness-builder.js +238 -0
  33. package/dist/midnight/witness-builder.js.map +1 -0
  34. package/dist/proofs/hash-chain-proof.d.ts +171 -0
  35. package/dist/proofs/hash-chain-proof.d.ts.map +1 -0
  36. package/dist/proofs/hash-chain-proof.js +437 -0
  37. package/dist/proofs/hash-chain-proof.js.map +1 -0
  38. package/dist/proofs/index.d.ts +35 -0
  39. package/dist/proofs/index.d.ts.map +1 -0
  40. package/dist/proofs/index.js +34 -0
  41. package/dist/proofs/index.js.map +1 -0
  42. package/dist/proofs/policy-compliance-proof.d.ts +165 -0
  43. package/dist/proofs/policy-compliance-proof.d.ts.map +1 -0
  44. package/dist/proofs/policy-compliance-proof.js +514 -0
  45. package/dist/proofs/policy-compliance-proof.js.map +1 -0
  46. package/dist/proofs/selective-disclosure.d.ts +213 -0
  47. package/dist/proofs/selective-disclosure.d.ts.map +1 -0
  48. package/dist/proofs/selective-disclosure.js +629 -0
  49. package/dist/proofs/selective-disclosure.js.map +1 -0
  50. package/dist/prover-interface.d.ts +288 -0
  51. package/dist/prover-interface.d.ts.map +1 -0
  52. package/dist/prover-interface.js +114 -0
  53. package/dist/prover-interface.js.map +1 -0
  54. package/dist/prover.d.ts +163 -0
  55. package/dist/prover.d.ts.map +1 -0
  56. package/dist/prover.js +417 -0
  57. package/dist/prover.js.map +1 -0
  58. package/dist/types.d.ts +410 -0
  59. package/dist/types.d.ts.map +1 -0
  60. package/dist/types.js +128 -0
  61. package/dist/types.js.map +1 -0
  62. package/package.json +59 -0
  63. package/src/__tests__/hash-chain-proof.test.ts +709 -0
  64. package/src/__tests__/midnight-prover.test.ts +716 -0
  65. package/src/__tests__/policy-compliance.test.ts +567 -0
  66. package/src/__tests__/proof-publication.test.ts +644 -0
  67. package/src/__tests__/selective-disclosure.test.ts +921 -0
  68. package/src/index.ts +260 -0
  69. package/src/linking/cardano-anchor-link.ts +682 -0
  70. package/src/linking/index.ts +58 -0
  71. package/src/linking/proof-publication.ts +557 -0
  72. package/src/midnight/index.ts +73 -0
  73. package/src/midnight/proof-server-client.ts +595 -0
  74. package/src/midnight/public-inputs.ts +590 -0
  75. package/src/midnight/witness-builder.ts +341 -0
  76. package/src/proofs/hash-chain-proof.ts +610 -0
  77. package/src/proofs/index.ts +77 -0
  78. package/src/proofs/policy-compliance-proof.ts +717 -0
  79. package/src/proofs/selective-disclosure.ts +839 -0
  80. package/src/prover-interface.ts +410 -0
  81. package/src/prover.ts +537 -0
  82. package/src/types.ts +551 -0
@@ -0,0 +1,716 @@
1
+ /**
2
+ * @fileoverview Integration tests for the DefaultMidnightProver.
3
+ *
4
+ * Location: packages/midnight-prover/src/__tests__/midnight-prover.test.ts
5
+ *
6
+ * Summary:
7
+ * Integration tests for the DefaultMidnightProver class which coordinates all
8
+ * proof types and handles the full lifecycle of proof generation and publication.
9
+ * Tests cover connection management, proof generation, publication, and verification.
10
+ *
11
+ * Usage:
12
+ * Run with: pnpm test -- packages/midnight-prover
13
+ *
14
+ * Related files:
15
+ * - prover.ts: DefaultMidnightProver implementation
16
+ * - prover-interface.ts: MidnightProver interface definition
17
+ * - proofs/: Individual prover implementations
18
+ * - linking/: Publication and cross-chain linking
19
+ */
20
+
21
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
22
+
23
+ import {
24
+ DefaultMidnightProver,
25
+ createMidnightProver,
26
+ } from "../prover.js";
27
+
28
+ import {
29
+ proverRegistry,
30
+ } from "../prover-interface.js";
31
+
32
+ import {
33
+ HashChainProver,
34
+ } from "../proofs/hash-chain-proof.js";
35
+
36
+ import {
37
+ PolicyComplianceProver,
38
+ } from "../proofs/policy-compliance-proof.js";
39
+
40
+ import {
41
+ SelectiveDisclosureProver,
42
+ } from "../proofs/selective-disclosure.js";
43
+
44
+ import {
45
+ CardanoAnchorLinker,
46
+ } from "../linking/cardano-anchor-link.js";
47
+
48
+ import {
49
+ buildHashChainWitness,
50
+ } from "../midnight/witness-builder.js";
51
+
52
+ import {
53
+ MidnightProverError,
54
+ MidnightProverException,
55
+ isHashChainProof,
56
+ isPolicyProof,
57
+ isDisclosureProof,
58
+ type HashChainInput,
59
+ type PolicyInput,
60
+ type DisclosureInput,
61
+ type ProofServerConfig,
62
+ } from "../types.js";
63
+
64
+ import type {
65
+ TraceEvent,
66
+ TraceBundle,
67
+ TraceSpan,
68
+ CommandEvent,
69
+ OutputEvent,
70
+ } from "@fluxpointstudios/orynq-sdk-process-trace";
71
+
72
+ // =============================================================================
73
+ // TEST HELPERS
74
+ // =============================================================================
75
+
76
+ /**
77
+ * Create a valid 64-character hex hash.
78
+ */
79
+ function createMockHash(seed: string): string {
80
+ const hex = "0123456789abcdef";
81
+ let result = "";
82
+ for (let i = 0; i < 64; i++) {
83
+ result += hex[(seed.charCodeAt(i % seed.length) + i) % 16];
84
+ }
85
+ return result;
86
+ }
87
+
88
+ /**
89
+ * Create a mock trace event.
90
+ */
91
+ function createMockEvent(seq: number, kind: string = "command"): TraceEvent {
92
+ const baseEvent = {
93
+ id: `event-${seq}-${Date.now()}`,
94
+ seq,
95
+ timestamp: new Date().toISOString(),
96
+ visibility: "public" as const,
97
+ };
98
+
99
+ if (kind === "command") {
100
+ return {
101
+ ...baseEvent,
102
+ kind: "command",
103
+ command: `test-command-${seq}`,
104
+ args: [`arg-${seq}`],
105
+ } as CommandEvent;
106
+ } else {
107
+ return {
108
+ ...baseEvent,
109
+ kind: "output",
110
+ stream: "stdout",
111
+ content: `output content ${seq}`,
112
+ } as OutputEvent;
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Create an array of mock events.
118
+ */
119
+ function createMockEvents(count: number): TraceEvent[] {
120
+ const events: TraceEvent[] = [];
121
+ for (let i = 1; i <= count; i++) {
122
+ events.push(createMockEvent(i, i % 2 === 0 ? "output" : "command"));
123
+ }
124
+ return events;
125
+ }
126
+
127
+ /**
128
+ * Create a mock trace span.
129
+ */
130
+ function createMockSpan(id: string, seq: number, eventIds: string[]): TraceSpan {
131
+ return {
132
+ id,
133
+ spanSeq: seq,
134
+ name: `span-${seq}`,
135
+ status: "completed",
136
+ visibility: "public",
137
+ startedAt: new Date().toISOString(),
138
+ endedAt: new Date().toISOString(),
139
+ durationMs: 100,
140
+ eventIds,
141
+ childSpanIds: [],
142
+ };
143
+ }
144
+
145
+ /**
146
+ * Create a mock trace bundle.
147
+ */
148
+ function createMockTraceBundle(): TraceBundle {
149
+ const events = createMockEvents(5);
150
+ const span1 = createMockSpan("span-1", 1, [events[0]!.id, events[1]!.id]);
151
+ const span2 = createMockSpan("span-2", 2, [events[2]!.id, events[3]!.id, events[4]!.id]);
152
+
153
+ return {
154
+ publicRun: {
155
+ sessionId: "session-123",
156
+ events: events.filter((_, i) => i < 2),
157
+ spans: [span1],
158
+ },
159
+ privateRun: {
160
+ sessionId: "session-123",
161
+ events,
162
+ spans: [span1, span2],
163
+ },
164
+ rootHash: createMockHash("root"),
165
+ merkleRoot: createMockHash("merkle"),
166
+ };
167
+ }
168
+
169
+ /**
170
+ * Create a mock proof server config.
171
+ */
172
+ function createMockConfig(): ProofServerConfig {
173
+ return {
174
+ proofServerUrl: "https://mock.proof.server",
175
+ apiKey: "test-api-key",
176
+ timeout: 30000,
177
+ retries: 3,
178
+ circuitCacheDir: undefined,
179
+ };
180
+ }
181
+
182
+ // =============================================================================
183
+ // DEFAULT MIDNIGHT PROVER TESTS
184
+ // =============================================================================
185
+
186
+ describe("DefaultMidnightProver", () => {
187
+ let prover: DefaultMidnightProver;
188
+ const config = createMockConfig();
189
+
190
+ beforeEach(async () => {
191
+ prover = new DefaultMidnightProver({ debug: false });
192
+ await prover.connect(config);
193
+ });
194
+
195
+ afterEach(async () => {
196
+ await prover.disconnect();
197
+ });
198
+
199
+ describe("constructor", () => {
200
+ it("should create a prover with default options", () => {
201
+ const defaultProver = new DefaultMidnightProver();
202
+ expect(defaultProver).toBeInstanceOf(DefaultMidnightProver);
203
+ expect(defaultProver.isConnected()).toBe(false);
204
+ });
205
+
206
+ it("should create a prover with custom options", () => {
207
+ const customProver = new DefaultMidnightProver({
208
+ debug: true,
209
+ circuitsDir: "./custom-circuits",
210
+ enableInference: false,
211
+ });
212
+ expect(customProver).toBeInstanceOf(DefaultMidnightProver);
213
+ });
214
+ });
215
+
216
+ describe("connection management", () => {
217
+ it("should connect and disconnect successfully", async () => {
218
+ const newProver = new DefaultMidnightProver();
219
+
220
+ expect(newProver.isConnected()).toBe(false);
221
+ await newProver.connect(config);
222
+ expect(newProver.isConnected()).toBe(true);
223
+ expect(newProver.getConfig()).toBeDefined();
224
+
225
+ await newProver.disconnect();
226
+ expect(newProver.isConnected()).toBe(false);
227
+ });
228
+
229
+ it("should throw for operations when not connected", async () => {
230
+ const disconnectedProver = new DefaultMidnightProver();
231
+
232
+ await expect(
233
+ disconnectedProver.proveHashChain({
234
+ events: createMockEvents(3),
235
+ genesisHash: createMockHash("genesis"),
236
+ expectedRootHash: createMockHash("root"),
237
+ cardanoAnchorTxHash: createMockHash("anchor"),
238
+ })
239
+ ).rejects.toThrow();
240
+ });
241
+ });
242
+
243
+ describe("proveHashChain", () => {
244
+ it("should generate a hash-chain proof", async () => {
245
+ const events = createMockEvents(5);
246
+ const genesisHash = await prover.getGenesisHash();
247
+ const witness = await buildHashChainWitness(events, genesisHash);
248
+
249
+ const input: HashChainInput = {
250
+ events,
251
+ genesisHash,
252
+ expectedRootHash: witness.computedRollingHash,
253
+ cardanoAnchorTxHash: createMockHash("anchor"),
254
+ };
255
+
256
+ const proof = await prover.proveHashChain(input);
257
+
258
+ expect(proof).toBeDefined();
259
+ expect(isHashChainProof(proof)).toBe(true);
260
+ expect(proof.proofId).toBeDefined();
261
+ expect(proof.publicInputs.rootHash).toBe(witness.computedRollingHash.toLowerCase());
262
+ expect(proof.publicInputs.eventCount).toBe(5);
263
+ });
264
+
265
+ it("should throw for invalid input", async () => {
266
+ const input: HashChainInput = {
267
+ events: [], // Empty events
268
+ genesisHash: createMockHash("genesis"),
269
+ expectedRootHash: createMockHash("root"),
270
+ cardanoAnchorTxHash: createMockHash("anchor"),
271
+ };
272
+
273
+ await expect(prover.proveHashChain(input)).rejects.toThrow(MidnightProverException);
274
+ });
275
+ });
276
+
277
+ describe("provePolicyCompliance", () => {
278
+ it("should generate a policy compliance proof", async () => {
279
+ const input: PolicyInput = {
280
+ promptHash: createMockHash("prompt"),
281
+ outputHash: createMockHash("output"),
282
+ policy: {
283
+ id: "test-policy",
284
+ version: "1.0.0",
285
+ rules: [
286
+ {
287
+ type: "blocklist",
288
+ target: "both",
289
+ params: { blockedHashes: [] },
290
+ },
291
+ ],
292
+ },
293
+ cardanoAnchorTxHash: createMockHash("anchor"),
294
+ };
295
+
296
+ const proof = await prover.provePolicyCompliance(input);
297
+
298
+ expect(proof).toBeDefined();
299
+ expect(isPolicyProof(proof)).toBe(true);
300
+ expect(proof.publicInputs.policyId).toBe("test-policy");
301
+ expect(proof.publicInputs.compliant).toBe(true);
302
+ });
303
+
304
+ it("should detect non-compliance", async () => {
305
+ const blockedHash = createMockHash("blocked");
306
+
307
+ const input: PolicyInput = {
308
+ promptHash: blockedHash,
309
+ outputHash: createMockHash("output"),
310
+ policy: {
311
+ id: "strict-policy",
312
+ version: "1.0.0",
313
+ rules: [
314
+ {
315
+ type: "blocklist",
316
+ target: "prompt",
317
+ params: { blockedHashes: [blockedHash] },
318
+ },
319
+ ],
320
+ },
321
+ cardanoAnchorTxHash: createMockHash("anchor"),
322
+ };
323
+
324
+ const proof = await prover.provePolicyCompliance(input);
325
+
326
+ expect(proof.publicInputs.compliant).toBe(false);
327
+ });
328
+ });
329
+
330
+ describe("proveSelectiveDisclosure", () => {
331
+ it("should generate a selective disclosure proof", async () => {
332
+ const bundle = createMockTraceBundle();
333
+
334
+ const input: DisclosureInput = {
335
+ bundle,
336
+ spanId: "span-1",
337
+ merkleRoot: bundle.merkleRoot ?? createMockHash("merkle"),
338
+ cardanoAnchorTxHash: createMockHash("anchor"),
339
+ };
340
+
341
+ // Note: The merkle root in the input must match what's computed from the spans
342
+ // For this test, we'll generate the proof but it may fail verification
343
+ // since we're using a mock merkle root
344
+
345
+ try {
346
+ const proof = await prover.proveSelectiveDisclosure(input);
347
+ expect(proof).toBeDefined();
348
+ expect(isDisclosureProof(proof)).toBe(true);
349
+ expect(proof.disclosedSpan).toBeDefined();
350
+ } catch (error) {
351
+ // Expected: hash mismatch since we're using mock merkle root
352
+ expect(error).toBeInstanceOf(MidnightProverException);
353
+ }
354
+ });
355
+
356
+ it("should throw for non-existent span", async () => {
357
+ const bundle = createMockTraceBundle();
358
+
359
+ const input: DisclosureInput = {
360
+ bundle,
361
+ spanId: "non-existent-span",
362
+ merkleRoot: createMockHash("merkle"),
363
+ cardanoAnchorTxHash: createMockHash("anchor"),
364
+ };
365
+
366
+ await expect(prover.proveSelectiveDisclosure(input)).rejects.toThrow(
367
+ MidnightProverException
368
+ );
369
+ });
370
+ });
371
+
372
+ describe("proveAttestation", () => {
373
+ it("should throw not implemented error", async () => {
374
+ const input = {
375
+ attestation: {} as never,
376
+ policy: {} as never,
377
+ cardanoAnchorTxHash: createMockHash("anchor"),
378
+ };
379
+
380
+ await expect(prover.proveAttestation(input)).rejects.toThrow(
381
+ /not yet implemented/i
382
+ );
383
+ });
384
+ });
385
+
386
+ describe("proveInference", () => {
387
+ it("should throw error when inference is disabled", async () => {
388
+ const input = {
389
+ modelId: "test-model",
390
+ modelWeightDigest: createMockHash("weights"),
391
+ inputTokens: [1, 2, 3],
392
+ outputTokens: [4, 5, 6],
393
+ params: {
394
+ temperature: 0.7,
395
+ topP: undefined,
396
+ topK: undefined,
397
+ maxTokens: 100,
398
+ stopStrings: undefined,
399
+ frequencyPenalty: undefined,
400
+ presencePenalty: undefined,
401
+ },
402
+ cardanoAnchorTxHash: createMockHash("anchor"),
403
+ };
404
+
405
+ expect(() => prover.proveInference(input)).toThrow(/disabled/i);
406
+ });
407
+
408
+ it("should throw not implemented even when enabled", async () => {
409
+ const enabledProver = new DefaultMidnightProver({ enableInference: true });
410
+ await enabledProver.connect(config);
411
+
412
+ const input = {
413
+ modelId: "test-model",
414
+ modelWeightDigest: createMockHash("weights"),
415
+ inputTokens: [1, 2, 3],
416
+ outputTokens: [4, 5, 6],
417
+ params: {
418
+ temperature: 0.7,
419
+ topP: undefined,
420
+ topK: undefined,
421
+ maxTokens: 100,
422
+ stopStrings: undefined,
423
+ frequencyPenalty: undefined,
424
+ presencePenalty: undefined,
425
+ },
426
+ cardanoAnchorTxHash: createMockHash("anchor"),
427
+ };
428
+
429
+ expect(() => enabledProver.proveInference(input)).toThrow(/not yet implemented/i);
430
+
431
+ await enabledProver.disconnect();
432
+ });
433
+ });
434
+
435
+ describe("publish", () => {
436
+ it("should publish a proof to the network", async () => {
437
+ const events = createMockEvents(3);
438
+ const genesisHash = await prover.getGenesisHash();
439
+ const witness = await buildHashChainWitness(events, genesisHash);
440
+
441
+ const hashChainProof = await prover.proveHashChain({
442
+ events,
443
+ genesisHash,
444
+ expectedRootHash: witness.computedRollingHash,
445
+ cardanoAnchorTxHash: createMockHash("anchor"),
446
+ });
447
+
448
+ const result = await prover.publish(hashChainProof);
449
+
450
+ expect(result).toBeDefined();
451
+ expect(result.midnightTxHash).toMatch(/^[0-9a-f]{64}$/);
452
+ expect(result.proofId).toBe(hashChainProof.proofId);
453
+ });
454
+ });
455
+
456
+ describe("verify", () => {
457
+ it("should verify a valid proof", async () => {
458
+ const events = createMockEvents(3);
459
+ const genesisHash = await prover.getGenesisHash();
460
+ const witness = await buildHashChainWitness(events, genesisHash);
461
+
462
+ const proof = await prover.proveHashChain({
463
+ events,
464
+ genesisHash,
465
+ expectedRootHash: witness.computedRollingHash,
466
+ cardanoAnchorTxHash: createMockHash("anchor"),
467
+ });
468
+
469
+ const result = await prover.verify(proof);
470
+
471
+ expect(result.valid).toBe(true);
472
+ expect(result.proofType).toBe("hash-chain");
473
+ expect(result.errors).toHaveLength(0);
474
+ });
475
+ });
476
+
477
+ describe("fetchProof", () => {
478
+ it("should return published proof from cache", async () => {
479
+ const events = createMockEvents(3);
480
+ const genesisHash = await prover.getGenesisHash();
481
+ const witness = await buildHashChainWitness(events, genesisHash);
482
+
483
+ const proof = await prover.proveHashChain({
484
+ events,
485
+ genesisHash,
486
+ expectedRootHash: witness.computedRollingHash,
487
+ cardanoAnchorTxHash: createMockHash("anchor"),
488
+ });
489
+
490
+ await prover.publish(proof);
491
+
492
+ const fetched = await prover.fetchProof(proof.proofId);
493
+
494
+ expect(fetched).toBeDefined();
495
+ expect(fetched?.proofId).toBe(proof.proofId);
496
+ });
497
+
498
+ it("should return undefined for unknown proof", async () => {
499
+ const fetched = await prover.fetchProof("unknown-proof-id");
500
+
501
+ expect(fetched).toBeUndefined();
502
+ });
503
+ });
504
+
505
+ describe("isPublished", () => {
506
+ it("should return true for published proof", async () => {
507
+ const events = createMockEvents(3);
508
+ const genesisHash = await prover.getGenesisHash();
509
+ const witness = await buildHashChainWitness(events, genesisHash);
510
+
511
+ const proof = await prover.proveHashChain({
512
+ events,
513
+ genesisHash,
514
+ expectedRootHash: witness.computedRollingHash,
515
+ cardanoAnchorTxHash: createMockHash("anchor"),
516
+ });
517
+
518
+ await prover.publish(proof);
519
+
520
+ const published = await prover.isPublished(proof.proofId);
521
+
522
+ expect(published).toBe(true);
523
+ });
524
+
525
+ it("should return false for unknown proof", async () => {
526
+ const published = await prover.isPublished("unknown-proof-id");
527
+
528
+ expect(published).toBe(false);
529
+ });
530
+ });
531
+
532
+ describe("waitForConfirmation", () => {
533
+ it("should wait for proof confirmation", async () => {
534
+ const events = createMockEvents(3);
535
+ const genesisHash = await prover.getGenesisHash();
536
+ const witness = await buildHashChainWitness(events, genesisHash);
537
+
538
+ const proof = await prover.proveHashChain({
539
+ events,
540
+ genesisHash,
541
+ expectedRootHash: witness.computedRollingHash,
542
+ cardanoAnchorTxHash: createMockHash("anchor"),
543
+ });
544
+
545
+ await prover.publish(proof);
546
+
547
+ const confirmed = await prover.waitForConfirmation(proof.proofId, 15000);
548
+
549
+ expect(confirmed).toBe(true);
550
+ });
551
+ });
552
+ });
553
+
554
+ // =============================================================================
555
+ // FACTORY FUNCTION TESTS
556
+ // =============================================================================
557
+
558
+ describe("createMidnightProver", () => {
559
+ it("should create a prover instance", () => {
560
+ const prover = createMidnightProver();
561
+ expect(prover).toBeInstanceOf(DefaultMidnightProver);
562
+ });
563
+
564
+ it("should create a prover with options", () => {
565
+ const prover = createMidnightProver({
566
+ debug: true,
567
+ enableInference: false,
568
+ });
569
+ expect(prover).toBeInstanceOf(DefaultMidnightProver);
570
+ });
571
+ });
572
+
573
+ // =============================================================================
574
+ // PROVER REGISTRY TESTS
575
+ // =============================================================================
576
+
577
+ describe("proverRegistry", () => {
578
+ it("should have default prover registered", () => {
579
+ const proverNames = proverRegistry.listProvers();
580
+ expect(proverNames).toContain("default");
581
+ });
582
+
583
+ it("should return default prover", () => {
584
+ const prover = proverRegistry.getDefault();
585
+ expect(prover).toBeDefined();
586
+ });
587
+
588
+ it("should get prover by name", () => {
589
+ const prover = proverRegistry.get("default");
590
+ expect(prover).toBeDefined();
591
+ });
592
+ });
593
+
594
+ // =============================================================================
595
+ // INTEGRATION: FULL FLOW TESTS
596
+ // =============================================================================
597
+
598
+ describe("Full Integration Flow", () => {
599
+ let prover: DefaultMidnightProver;
600
+ let linker: CardanoAnchorLinker;
601
+ const config = createMockConfig();
602
+
603
+ beforeEach(async () => {
604
+ prover = new DefaultMidnightProver({ debug: false });
605
+ linker = new CardanoAnchorLinker({ debug: false });
606
+ await prover.connect(config);
607
+ });
608
+
609
+ afterEach(async () => {
610
+ await prover.disconnect();
611
+ });
612
+
613
+ it("should complete full proof lifecycle: generate -> publish -> link -> verify", async () => {
614
+ // 1. Generate proof
615
+ const events = createMockEvents(5);
616
+ const genesisHash = await prover.getGenesisHash();
617
+ const witness = await buildHashChainWitness(events, genesisHash);
618
+ const cardanoAnchorTxHash = createMockHash("cardano-anchor");
619
+
620
+ const proof = await prover.proveHashChain({
621
+ events,
622
+ genesisHash,
623
+ expectedRootHash: witness.computedRollingHash,
624
+ cardanoAnchorTxHash,
625
+ });
626
+
627
+ expect(proof).toBeDefined();
628
+ expect(proof.proofType).toBe("hash-chain");
629
+
630
+ // 2. Publish proof
631
+ const publicationResult = await prover.publish(proof);
632
+
633
+ expect(publicationResult.midnightTxHash).toBeDefined();
634
+ expect(publicationResult.proofId).toBe(proof.proofId);
635
+
636
+ // 3. Create cross-chain link
637
+ const link = linker.linkToAnchor(
638
+ proof,
639
+ cardanoAnchorTxHash,
640
+ publicationResult.midnightTxHash
641
+ );
642
+
643
+ expect(link).toBeDefined();
644
+ expect(link.midnightProofId).toBe(proof.proofId);
645
+ expect(link.midnightTxHash).toBe(publicationResult.midnightTxHash);
646
+ expect(link.cardanoAnchorTxHash).toBe(cardanoAnchorTxHash.toLowerCase());
647
+
648
+ // 4. Verify link
649
+ const linkVerification = await linker.verifyLink(link);
650
+
651
+ expect(linkVerification.valid).toBe(true);
652
+ expect(linkVerification.commitmentVerified).toBe(true);
653
+
654
+ // 5. Verify proof
655
+ const proofVerification = await prover.verify(proof);
656
+
657
+ expect(proofVerification.valid).toBe(true);
658
+
659
+ // 6. Check publication status
660
+ const published = await prover.isPublished(proof.proofId);
661
+
662
+ expect(published).toBe(true);
663
+ });
664
+
665
+ it("should handle multiple proof types for the same anchor", async () => {
666
+ const cardanoAnchorTxHash = createMockHash("shared-anchor");
667
+
668
+ // Generate hash-chain proof
669
+ const events = createMockEvents(3);
670
+ const genesisHash = await prover.getGenesisHash();
671
+ const witness = await buildHashChainWitness(events, genesisHash);
672
+
673
+ const hashChainProof = await prover.proveHashChain({
674
+ events,
675
+ genesisHash,
676
+ expectedRootHash: witness.computedRollingHash,
677
+ cardanoAnchorTxHash,
678
+ });
679
+
680
+ // Generate policy proof
681
+ const policyProof = await prover.provePolicyCompliance({
682
+ promptHash: createMockHash("prompt"),
683
+ outputHash: createMockHash("output"),
684
+ policy: {
685
+ id: "test-policy",
686
+ version: "1.0.0",
687
+ rules: [],
688
+ },
689
+ cardanoAnchorTxHash,
690
+ });
691
+
692
+ // Publish both
693
+ const hashChainResult = await prover.publish(hashChainProof);
694
+ const policyResult = await prover.publish(policyProof);
695
+
696
+ // Create links
697
+ const hashChainLink = linker.linkToAnchor(
698
+ hashChainProof,
699
+ cardanoAnchorTxHash,
700
+ hashChainResult.midnightTxHash
701
+ );
702
+
703
+ const policyLink = linker.linkToAnchor(
704
+ policyProof,
705
+ cardanoAnchorTxHash,
706
+ policyResult.midnightTxHash
707
+ );
708
+
709
+ // Both links should reference the same Cardano anchor
710
+ expect(hashChainLink.cardanoAnchorTxHash).toBe(policyLink.cardanoAnchorTxHash);
711
+
712
+ // Should be able to find both links by anchor
713
+ const anchorLinks = linker.getLinksByCardanoAnchor(cardanoAnchorTxHash);
714
+ expect(anchorLinks).toHaveLength(2);
715
+ });
716
+ });