@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,610 @@
1
+ /**
2
+ * @fileoverview Hash-chain validity proof generator.
3
+ *
4
+ * Location: packages/midnight-prover/src/proofs/hash-chain-proof.ts
5
+ *
6
+ * Summary:
7
+ * This module implements the HashChainProver class which generates and verifies
8
+ * ZK proofs that a sequence of trace events produces an expected rolling hash.
9
+ * The proof is bound to a Cardano anchor transaction for cross-chain verification.
10
+ *
11
+ * Usage:
12
+ * The HashChainProver is the primary prover for PoI trace verification:
13
+ * ```typescript
14
+ * const prover = new HashChainProver();
15
+ * const proof = await prover.generateProof({
16
+ * events: traceBundle.privateRun.events,
17
+ * genesisHash: await getGenesisHash(),
18
+ * expectedRootHash: traceBundle.rootHash,
19
+ * cardanoAnchorTxHash: anchorTxHash,
20
+ * });
21
+ * const isValid = await prover.verifyProof(proof);
22
+ * ```
23
+ *
24
+ * Related files:
25
+ * - witness-builder.ts: Builds witnesses for this prover
26
+ * - public-inputs.ts: Builds public inputs for this prover
27
+ * - prover-interface.ts: Abstract interface this implements
28
+ * - types.ts: Type definitions for inputs and outputs
29
+ */
30
+
31
+ import { randomUUID } from "node:crypto";
32
+
33
+ import type {
34
+ HashChainInput,
35
+ HashChainProof,
36
+ HashChainPublicInputs,
37
+ } from "../types.js";
38
+
39
+ import {
40
+ MidnightProverError,
41
+ MidnightProverException,
42
+ } from "../types.js";
43
+
44
+ import {
45
+ buildHashChainWitness,
46
+ serializeWitness,
47
+ computeWitnessSize,
48
+ validateWitness,
49
+ type HashChainWitness,
50
+ } from "../midnight/witness-builder.js";
51
+
52
+ import {
53
+ buildPublicInputs,
54
+ serializePublicInputs,
55
+ } from "../midnight/public-inputs.js";
56
+
57
+ import { sha256StringHex } from "@fluxpointstudios/orynq-sdk-core/utils";
58
+
59
+ // =============================================================================
60
+ // CONSTANTS
61
+ // =============================================================================
62
+
63
+ /**
64
+ * Maximum number of events allowed in a single hash-chain proof.
65
+ * This limit is imposed by circuit constraints.
66
+ */
67
+ const MAX_EVENTS_PER_PROOF = 10_000;
68
+
69
+ /**
70
+ * Maximum witness size in bytes (50 MB).
71
+ */
72
+ const MAX_WITNESS_SIZE_BYTES = 50 * 1024 * 1024;
73
+
74
+ /**
75
+ * Hash domain prefix for rolling hash (matching process-trace).
76
+ */
77
+ const HASH_DOMAIN_ROLL = "poi-trace:roll:v1|";
78
+
79
+ /**
80
+ * Genesis seed for initial rolling hash state.
81
+ */
82
+ const GENESIS_SEED = "genesis";
83
+
84
+ // =============================================================================
85
+ // HASH CHAIN PROVER
86
+ // =============================================================================
87
+
88
+ /**
89
+ * Options for HashChainProver configuration.
90
+ */
91
+ export interface HashChainProverOptions {
92
+ /**
93
+ * Enable debug logging.
94
+ */
95
+ debug?: boolean;
96
+
97
+ /**
98
+ * Maximum events per proof (defaults to MAX_EVENTS_PER_PROOF).
99
+ */
100
+ maxEvents?: number;
101
+
102
+ /**
103
+ * Simulated proving time in milliseconds (for mock mode).
104
+ * Set to 0 for instant proofs (useful in tests).
105
+ */
106
+ simulatedProvingTimeMs?: number;
107
+ }
108
+
109
+ /**
110
+ * HashChainProver generates and verifies ZK proofs for trace hash chains.
111
+ *
112
+ * This prover demonstrates that:
113
+ * 1. A sequence of events exists (private witness)
114
+ * 2. Processing them produces a specific rolling hash (public input)
115
+ * 3. This hash matches what was anchored on Cardano (cross-chain binding)
116
+ *
117
+ * Current implementation is a mock that simulates proof generation.
118
+ * Real Midnight integration will be added when the Compact runtime is available.
119
+ *
120
+ * @example
121
+ * ```typescript
122
+ * const prover = new HashChainProver({ debug: true });
123
+ *
124
+ * const proof = await prover.generateProof({
125
+ * events: bundle.privateRun.events,
126
+ * genesisHash: "abc123...",
127
+ * expectedRootHash: bundle.rootHash,
128
+ * cardanoAnchorTxHash: "def456...",
129
+ * });
130
+ *
131
+ * console.log("Proof generated:", proof.proofId);
132
+ * console.log("Proving time:", proof.provingTimeMs, "ms");
133
+ *
134
+ * const isValid = await prover.verifyProof(proof);
135
+ * console.log("Proof valid:", isValid);
136
+ * ```
137
+ */
138
+ export class HashChainProver {
139
+ private readonly options: Required<HashChainProverOptions>;
140
+
141
+ /**
142
+ * Create a new HashChainProver.
143
+ *
144
+ * @param options - Configuration options
145
+ */
146
+ constructor(options: HashChainProverOptions = {}) {
147
+ this.options = {
148
+ debug: options.debug ?? false,
149
+ maxEvents: options.maxEvents ?? MAX_EVENTS_PER_PROOF,
150
+ simulatedProvingTimeMs: options.simulatedProvingTimeMs ?? 100,
151
+ };
152
+ }
153
+
154
+ /**
155
+ * Generate a hash-chain validity proof.
156
+ *
157
+ * This method:
158
+ * 1. Validates the input
159
+ * 2. Builds a witness from the events
160
+ * 3. Verifies the computed hash matches expected
161
+ * 4. Generates a mock ZK proof
162
+ * 5. Returns the proof with metrics
163
+ *
164
+ * @param input - Hash chain input with events and expected hash
165
+ * @returns Promise resolving to the generated proof
166
+ * @throws MidnightProverException on validation or generation failure
167
+ */
168
+ async generateProof(input: HashChainInput): Promise<HashChainProof> {
169
+ const startTime = Date.now();
170
+
171
+ this.debug("Starting hash-chain proof generation");
172
+ this.debug(`Events: ${input.events.length}`);
173
+
174
+ // Validate input
175
+ this.validateInput(input);
176
+
177
+ // Build witness
178
+ const witness = await this.buildWitness(input);
179
+
180
+ // Verify hash matches expected
181
+ await this.verifyHashMatch(witness, input);
182
+
183
+ // Build public inputs
184
+ const publicInputs = this.buildPublicInputs(witness, input);
185
+
186
+ // Generate mock proof
187
+ const proofBytes = await this.generateMockProof(witness, publicInputs);
188
+
189
+ // Calculate metrics
190
+ const provingTimeMs = Date.now() - startTime + this.options.simulatedProvingTimeMs;
191
+
192
+ // Simulate proving delay
193
+ if (this.options.simulatedProvingTimeMs > 0) {
194
+ await this.delay(this.options.simulatedProvingTimeMs);
195
+ }
196
+
197
+ const proof: HashChainProof = {
198
+ proofType: "hash-chain",
199
+ proofId: randomUUID(),
200
+ proof: proofBytes,
201
+ createdAt: new Date().toISOString(),
202
+ provingTimeMs,
203
+ proofSizeBytes: proofBytes.length,
204
+ publicInputs,
205
+ };
206
+
207
+ this.debug(`Proof generated: ${proof.proofId}`);
208
+ this.debug(`Proving time: ${proof.provingTimeMs}ms`);
209
+ this.debug(`Proof size: ${proof.proofSizeBytes} bytes`);
210
+
211
+ return proof;
212
+ }
213
+
214
+ /**
215
+ * Verify a hash-chain proof.
216
+ *
217
+ * This method checks:
218
+ * 1. Proof format is valid
219
+ * 2. Public inputs are consistent
220
+ * 3. Mock proof data is correctly structured
221
+ *
222
+ * Note: In production, this would verify the actual ZK proof.
223
+ * Current mock implementation verifies structural integrity.
224
+ *
225
+ * @param proof - The proof to verify
226
+ * @returns Promise resolving to true if valid, false otherwise
227
+ */
228
+ async verifyProof(proof: HashChainProof): Promise<boolean> {
229
+ this.debug(`Verifying proof: ${proof.proofId}`);
230
+
231
+ try {
232
+ // Validate proof structure
233
+ if (proof.proofType !== "hash-chain") {
234
+ this.debug("Invalid proof type");
235
+ return false;
236
+ }
237
+
238
+ if (!proof.proof || proof.proof.length === 0) {
239
+ this.debug("Empty proof data");
240
+ return false;
241
+ }
242
+
243
+ // Validate public inputs
244
+ const { publicInputs } = proof;
245
+
246
+ if (!isValidHexHash(publicInputs.rootHash)) {
247
+ this.debug("Invalid rootHash format");
248
+ return false;
249
+ }
250
+
251
+ if (!isValidHexHash(publicInputs.cardanoAnchorTxHash)) {
252
+ this.debug("Invalid cardanoAnchorTxHash format");
253
+ return false;
254
+ }
255
+
256
+ if (!Number.isInteger(publicInputs.eventCount) || publicInputs.eventCount < 0) {
257
+ this.debug("Invalid eventCount");
258
+ return false;
259
+ }
260
+
261
+ // Verify mock proof structure
262
+ const isValidMockProof = await this.verifyMockProofStructure(proof);
263
+ if (!isValidMockProof) {
264
+ this.debug("Mock proof structure invalid");
265
+ return false;
266
+ }
267
+
268
+ this.debug("Proof verified successfully");
269
+ return true;
270
+ } catch (error) {
271
+ this.debug(`Verification error: ${error}`);
272
+ return false;
273
+ }
274
+ }
275
+
276
+ /**
277
+ * Compute the genesis hash for the rolling hash chain.
278
+ * This matches the algorithm in process-trace/rolling-hash.ts
279
+ *
280
+ * @returns Promise resolving to the genesis hash
281
+ */
282
+ async getGenesisHash(): Promise<string> {
283
+ const genesisInput = HASH_DOMAIN_ROLL + GENESIS_SEED;
284
+ return sha256StringHex(genesisInput);
285
+ }
286
+
287
+ // ===========================================================================
288
+ // PRIVATE METHODS
289
+ // ===========================================================================
290
+
291
+ /**
292
+ * Validate the input for proof generation.
293
+ */
294
+ private validateInput(input: HashChainInput): void {
295
+ // Check events array
296
+ if (!Array.isArray(input.events)) {
297
+ throw new MidnightProverException(
298
+ MidnightProverError.INVALID_INPUT,
299
+ "events must be an array"
300
+ );
301
+ }
302
+
303
+ if (input.events.length === 0) {
304
+ throw new MidnightProverException(
305
+ MidnightProverError.INVALID_INPUT,
306
+ "events array is empty"
307
+ );
308
+ }
309
+
310
+ if (input.events.length > this.options.maxEvents) {
311
+ throw new MidnightProverException(
312
+ MidnightProverError.WITNESS_TOO_LARGE,
313
+ `Too many events: ${input.events.length} exceeds maximum ${this.options.maxEvents}`
314
+ );
315
+ }
316
+
317
+ // Check hash formats
318
+ if (!isValidHexHash(input.genesisHash)) {
319
+ throw new MidnightProverException(
320
+ MidnightProverError.INVALID_INPUT,
321
+ `Invalid genesisHash format: ${input.genesisHash}`
322
+ );
323
+ }
324
+
325
+ if (!isValidHexHash(input.expectedRootHash)) {
326
+ throw new MidnightProverException(
327
+ MidnightProverError.INVALID_INPUT,
328
+ `Invalid expectedRootHash format: ${input.expectedRootHash}`
329
+ );
330
+ }
331
+
332
+ if (!isValidHexHash(input.cardanoAnchorTxHash)) {
333
+ throw new MidnightProverException(
334
+ MidnightProverError.INVALID_INPUT,
335
+ `Invalid cardanoAnchorTxHash format: ${input.cardanoAnchorTxHash}`
336
+ );
337
+ }
338
+
339
+ // Validate events have required fields
340
+ for (let i = 0; i < input.events.length; i++) {
341
+ const event = input.events[i];
342
+ if (event === undefined) {
343
+ throw new MidnightProverException(
344
+ MidnightProverError.INVALID_INPUT,
345
+ `Event at index ${i} is undefined`
346
+ );
347
+ }
348
+
349
+ if (typeof event.seq !== "number") {
350
+ throw new MidnightProverException(
351
+ MidnightProverError.INVALID_INPUT,
352
+ `Event at index ${i} missing seq number`
353
+ );
354
+ }
355
+
356
+ if (typeof event.kind !== "string") {
357
+ throw new MidnightProverException(
358
+ MidnightProverError.INVALID_INPUT,
359
+ `Event at index ${i} missing kind`
360
+ );
361
+ }
362
+ }
363
+ }
364
+
365
+ /**
366
+ * Build the witness from input.
367
+ */
368
+ private async buildWitness(input: HashChainInput): Promise<HashChainWitness> {
369
+ this.debug("Building witness...");
370
+
371
+ const witness = await buildHashChainWitness(
372
+ input.events,
373
+ normalizeHash(input.genesisHash)
374
+ );
375
+
376
+ // Validate witness
377
+ const validationErrors = validateWitness(witness);
378
+ if (validationErrors.length > 0) {
379
+ throw new MidnightProverException(
380
+ MidnightProverError.INVALID_WITNESS,
381
+ `Witness validation failed: ${validationErrors.join(", ")}`
382
+ );
383
+ }
384
+
385
+ // Check witness size
386
+ const witnessSize = computeWitnessSize(witness);
387
+ if (witnessSize > MAX_WITNESS_SIZE_BYTES) {
388
+ throw new MidnightProverException(
389
+ MidnightProverError.WITNESS_TOO_LARGE,
390
+ `Witness size ${witnessSize} bytes exceeds maximum ${MAX_WITNESS_SIZE_BYTES}`
391
+ );
392
+ }
393
+
394
+ this.debug(`Witness built: ${witness.eventCount} events, ${witnessSize} bytes`);
395
+
396
+ return witness;
397
+ }
398
+
399
+ /**
400
+ * Verify that the computed rolling hash matches the expected root hash.
401
+ */
402
+ private async verifyHashMatch(
403
+ witness: HashChainWitness,
404
+ input: HashChainInput
405
+ ): Promise<void> {
406
+ const computedHash = normalizeHash(witness.computedRollingHash);
407
+ const expectedHash = normalizeHash(input.expectedRootHash);
408
+
409
+ if (computedHash !== expectedHash) {
410
+ throw new MidnightProverException(
411
+ MidnightProverError.HASH_MISMATCH,
412
+ `Rolling hash mismatch: computed ${computedHash}, expected ${expectedHash}`
413
+ );
414
+ }
415
+
416
+ this.debug("Hash match verified");
417
+ }
418
+
419
+ /**
420
+ * Build public inputs for the proof.
421
+ */
422
+ private buildPublicInputs(
423
+ witness: HashChainWitness,
424
+ input: HashChainInput
425
+ ): HashChainPublicInputs {
426
+ return buildPublicInputs("hash-chain", {
427
+ rootHash: witness.computedRollingHash,
428
+ eventCount: witness.eventCount,
429
+ cardanoAnchorTxHash: input.cardanoAnchorTxHash,
430
+ });
431
+ }
432
+
433
+ /**
434
+ * Generate a mock ZK proof.
435
+ *
436
+ * This creates a simulated proof structure that includes:
437
+ * - A magic header identifying it as a mock proof
438
+ * - Hash of the witness (for integrity)
439
+ * - Serialized public inputs
440
+ * - Random "proof" bytes (placeholder for real proof data)
441
+ *
442
+ * In production, this would call the Midnight proof server.
443
+ */
444
+ private async generateMockProof(
445
+ witness: HashChainWitness,
446
+ publicInputs: HashChainPublicInputs
447
+ ): Promise<Uint8Array> {
448
+ // Magic header for mock proofs: "MOCK-POI-HC-PROOF-V1"
449
+ const magicHeader = new TextEncoder().encode("MOCK-POI-HC-PROOF-V1");
450
+
451
+ // Compute witness hash for integrity
452
+ const serializedWitness = serializeWitness(witness);
453
+ // Copy to a fresh ArrayBuffer to ensure compatibility with crypto.subtle.digest
454
+ const witnessBuffer = new ArrayBuffer(serializedWitness.byteLength);
455
+ new Uint8Array(witnessBuffer).set(serializedWitness);
456
+ const witnessHashBuffer = await crypto.subtle.digest("SHA-256", witnessBuffer);
457
+ const witnessHash = new Uint8Array(witnessHashBuffer);
458
+
459
+ // Serialize public inputs
460
+ const serializedPublicInputs = serializePublicInputs("hash-chain", publicInputs);
461
+
462
+ // Generate random "proof" data (256 bytes)
463
+ const randomProofData = new Uint8Array(256);
464
+ crypto.getRandomValues(randomProofData);
465
+
466
+ // Combine all parts
467
+ const proof = new Uint8Array(
468
+ magicHeader.length + // 20 bytes
469
+ 4 + // witness hash length (4 bytes, always 32)
470
+ witnessHash.length + // 32 bytes
471
+ 4 + // public inputs length
472
+ serializedPublicInputs.length +
473
+ 4 + // proof data length
474
+ randomProofData.length
475
+ );
476
+
477
+ let offset = 0;
478
+
479
+ // Write magic header
480
+ proof.set(magicHeader, offset);
481
+ offset += magicHeader.length;
482
+
483
+ // Write witness hash
484
+ const view = new DataView(proof.buffer);
485
+ view.setUint32(offset, witnessHash.length, false);
486
+ offset += 4;
487
+ proof.set(witnessHash, offset);
488
+ offset += witnessHash.length;
489
+
490
+ // Write public inputs
491
+ view.setUint32(offset, serializedPublicInputs.length, false);
492
+ offset += 4;
493
+ proof.set(serializedPublicInputs, offset);
494
+ offset += serializedPublicInputs.length;
495
+
496
+ // Write random proof data
497
+ view.setUint32(offset, randomProofData.length, false);
498
+ offset += 4;
499
+ proof.set(randomProofData, offset);
500
+
501
+ return proof;
502
+ }
503
+
504
+ /**
505
+ * Verify the structure of a mock proof.
506
+ */
507
+ private async verifyMockProofStructure(proof: HashChainProof): Promise<boolean> {
508
+ const data = proof.proof;
509
+
510
+ // Check minimum length
511
+ if (data.length < 20 + 4 + 32 + 4 + 1 + 4 + 1) {
512
+ return false;
513
+ }
514
+
515
+ // Check magic header
516
+ const magicHeader = new TextDecoder().decode(data.slice(0, 20));
517
+ if (magicHeader !== "MOCK-POI-HC-PROOF-V1") {
518
+ return false;
519
+ }
520
+
521
+ // Verify structure can be parsed
522
+ try {
523
+ let offset = 20;
524
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
525
+
526
+ // Witness hash
527
+ const witnessHashLen = view.getUint32(offset, false);
528
+ offset += 4;
529
+ if (witnessHashLen !== 32 || offset + witnessHashLen > data.length) {
530
+ return false;
531
+ }
532
+ offset += witnessHashLen;
533
+
534
+ // Public inputs
535
+ const publicInputsLen = view.getUint32(offset, false);
536
+ offset += 4;
537
+ if (offset + publicInputsLen > data.length) {
538
+ return false;
539
+ }
540
+ offset += publicInputsLen;
541
+
542
+ // Proof data
543
+ const proofDataLen = view.getUint32(offset, false);
544
+ offset += 4;
545
+ if (offset + proofDataLen > data.length) {
546
+ return false;
547
+ }
548
+
549
+ return true;
550
+ } catch {
551
+ return false;
552
+ }
553
+ }
554
+
555
+ /**
556
+ * Debug logging helper.
557
+ */
558
+ private debug(message: string): void {
559
+ if (this.options.debug) {
560
+ console.log(`[HashChainProver] ${message}`);
561
+ }
562
+ }
563
+
564
+ /**
565
+ * Delay helper for simulated proving time.
566
+ */
567
+ private delay(ms: number): Promise<void> {
568
+ return new Promise((resolve) => setTimeout(resolve, ms));
569
+ }
570
+ }
571
+
572
+ // =============================================================================
573
+ // UTILITY FUNCTIONS
574
+ // =============================================================================
575
+
576
+ /**
577
+ * Validate a hex hash string (64 characters, with or without 0x prefix).
578
+ */
579
+ function isValidHexHash(value: string): boolean {
580
+ if (typeof value !== "string") {
581
+ return false;
582
+ }
583
+
584
+ const cleanHex = value.startsWith("0x") ? value.slice(2) : value;
585
+ return /^[0-9a-fA-F]{64}$/.test(cleanHex);
586
+ }
587
+
588
+ /**
589
+ * Normalize a hash to lowercase without 0x prefix.
590
+ */
591
+ function normalizeHash(hash: string): string {
592
+ const cleanHex = hash.startsWith("0x") ? hash.slice(2) : hash;
593
+ return cleanHex.toLowerCase();
594
+ }
595
+
596
+ // =============================================================================
597
+ // FACTORY FUNCTION
598
+ // =============================================================================
599
+
600
+ /**
601
+ * Create a new HashChainProver instance.
602
+ *
603
+ * @param options - Configuration options
604
+ * @returns A new HashChainProver instance
605
+ */
606
+ export function createHashChainProver(
607
+ options?: HashChainProverOptions
608
+ ): HashChainProver {
609
+ return new HashChainProver(options);
610
+ }
@@ -0,0 +1,77 @@
1
+ /**
2
+ * @fileoverview Proof generators exports.
3
+ *
4
+ * Location: packages/midnight-prover/src/proofs/index.ts
5
+ *
6
+ * Summary:
7
+ * This file exports all proof generator classes and factory functions.
8
+ * Each prover handles a specific type of ZK proof for the PoI system.
9
+ *
10
+ * Usage:
11
+ * ```typescript
12
+ * import {
13
+ * HashChainProver,
14
+ * PolicyComplianceProver,
15
+ * SelectiveDisclosureProver,
16
+ * createHashChainProver,
17
+ * } from "@fluxpointstudios/orynq-sdk-midnight-prover";
18
+ *
19
+ * const prover = createHashChainProver({ debug: true });
20
+ * const proof = await prover.generateProof(input);
21
+ * ```
22
+ *
23
+ * Related files:
24
+ * - hash-chain-proof.ts: Hash chain validity proofs
25
+ * - policy-compliance-proof.ts: Policy compliance proofs
26
+ * - selective-disclosure.ts: Selective disclosure proofs with Merkle utilities
27
+ * - (future) attestation-proof.ts: TEE attestation proofs
28
+ */
29
+
30
+ // =============================================================================
31
+ // HASH CHAIN PROVER
32
+ // =============================================================================
33
+
34
+ export type { HashChainProverOptions } from "./hash-chain-proof.js";
35
+
36
+ export {
37
+ HashChainProver,
38
+ createHashChainProver,
39
+ } from "./hash-chain-proof.js";
40
+
41
+ // =============================================================================
42
+ // POLICY COMPLIANCE PROVER
43
+ // =============================================================================
44
+
45
+ export type {
46
+ PolicyComplianceProverOptions,
47
+ RuleEvaluationResult,
48
+ PolicyEvaluationResult,
49
+ RuleEvaluator,
50
+ } from "./policy-compliance-proof.js";
51
+
52
+ export {
53
+ PolicyComplianceProver,
54
+ createPolicyComplianceProver,
55
+ } from "./policy-compliance-proof.js";
56
+
57
+ // =============================================================================
58
+ // SELECTIVE DISCLOSURE PROVER
59
+ // =============================================================================
60
+
61
+ export type {
62
+ SelectiveDisclosureProverOptions,
63
+ MerkleInclusionResult,
64
+ } from "./selective-disclosure.js";
65
+
66
+ export {
67
+ SelectiveDisclosureProver,
68
+ createSelectiveDisclosureProver,
69
+ // Merkle utilities
70
+ computeSpanHash,
71
+ computeLeafHash,
72
+ computeNodeHash,
73
+ computeMerkleRoot,
74
+ generateMerkleInclusionProof,
75
+ verifyMerkleProof,
76
+ verifySpanInclusion,
77
+ } from "./selective-disclosure.js";