@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.
- package/LICENSE +21 -0
- package/dist/index.d.ts +78 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +89 -0
- package/dist/index.js.map +1 -0
- package/dist/linking/cardano-anchor-link.d.ts +250 -0
- package/dist/linking/cardano-anchor-link.d.ts.map +1 -0
- package/dist/linking/cardano-anchor-link.js +447 -0
- package/dist/linking/cardano-anchor-link.js.map +1 -0
- package/dist/linking/index.d.ts +33 -0
- package/dist/linking/index.d.ts.map +1 -0
- package/dist/linking/index.js +31 -0
- package/dist/linking/index.js.map +1 -0
- package/dist/linking/proof-publication.d.ts +217 -0
- package/dist/linking/proof-publication.d.ts.map +1 -0
- package/dist/linking/proof-publication.js +385 -0
- package/dist/linking/proof-publication.js.map +1 -0
- package/dist/midnight/index.d.ts +30 -0
- package/dist/midnight/index.d.ts.map +1 -0
- package/dist/midnight/index.js +27 -0
- package/dist/midnight/index.js.map +1 -0
- package/dist/midnight/proof-server-client.d.ts +236 -0
- package/dist/midnight/proof-server-client.d.ts.map +1 -0
- package/dist/midnight/proof-server-client.js +422 -0
- package/dist/midnight/proof-server-client.js.map +1 -0
- package/dist/midnight/public-inputs.d.ts +134 -0
- package/dist/midnight/public-inputs.d.ts.map +1 -0
- package/dist/midnight/public-inputs.js +338 -0
- package/dist/midnight/public-inputs.js.map +1 -0
- package/dist/midnight/witness-builder.d.ts +119 -0
- package/dist/midnight/witness-builder.d.ts.map +1 -0
- package/dist/midnight/witness-builder.js +238 -0
- package/dist/midnight/witness-builder.js.map +1 -0
- package/dist/proofs/hash-chain-proof.d.ts +171 -0
- package/dist/proofs/hash-chain-proof.d.ts.map +1 -0
- package/dist/proofs/hash-chain-proof.js +437 -0
- package/dist/proofs/hash-chain-proof.js.map +1 -0
- package/dist/proofs/index.d.ts +35 -0
- package/dist/proofs/index.d.ts.map +1 -0
- package/dist/proofs/index.js +34 -0
- package/dist/proofs/index.js.map +1 -0
- package/dist/proofs/policy-compliance-proof.d.ts +165 -0
- package/dist/proofs/policy-compliance-proof.d.ts.map +1 -0
- package/dist/proofs/policy-compliance-proof.js +514 -0
- package/dist/proofs/policy-compliance-proof.js.map +1 -0
- package/dist/proofs/selective-disclosure.d.ts +213 -0
- package/dist/proofs/selective-disclosure.d.ts.map +1 -0
- package/dist/proofs/selective-disclosure.js +629 -0
- package/dist/proofs/selective-disclosure.js.map +1 -0
- package/dist/prover-interface.d.ts +288 -0
- package/dist/prover-interface.d.ts.map +1 -0
- package/dist/prover-interface.js +114 -0
- package/dist/prover-interface.js.map +1 -0
- package/dist/prover.d.ts +163 -0
- package/dist/prover.d.ts.map +1 -0
- package/dist/prover.js +417 -0
- package/dist/prover.js.map +1 -0
- package/dist/types.d.ts +410 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +128 -0
- package/dist/types.js.map +1 -0
- package/package.json +59 -0
- package/src/__tests__/hash-chain-proof.test.ts +709 -0
- package/src/__tests__/midnight-prover.test.ts +716 -0
- package/src/__tests__/policy-compliance.test.ts +567 -0
- package/src/__tests__/proof-publication.test.ts +644 -0
- package/src/__tests__/selective-disclosure.test.ts +921 -0
- package/src/index.ts +260 -0
- package/src/linking/cardano-anchor-link.ts +682 -0
- package/src/linking/index.ts +58 -0
- package/src/linking/proof-publication.ts +557 -0
- package/src/midnight/index.ts +73 -0
- package/src/midnight/proof-server-client.ts +595 -0
- package/src/midnight/public-inputs.ts +590 -0
- package/src/midnight/witness-builder.ts +341 -0
- package/src/proofs/hash-chain-proof.ts +610 -0
- package/src/proofs/index.ts +77 -0
- package/src/proofs/policy-compliance-proof.ts +717 -0
- package/src/proofs/selective-disclosure.ts +839 -0
- package/src/prover-interface.ts +410 -0
- package/src/prover.ts +537 -0
- package/src/types.ts +551 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Linking module exports for cross-chain operations.
|
|
3
|
+
*
|
|
4
|
+
* Location: packages/midnight-prover/src/linking/index.ts
|
|
5
|
+
*
|
|
6
|
+
* Summary:
|
|
7
|
+
* This file exports all linking-related classes and utilities for:
|
|
8
|
+
* - Publishing proofs to the Midnight network
|
|
9
|
+
* - Creating cross-chain links between Midnight proofs and Cardano anchors
|
|
10
|
+
* - Verifying cross-chain relationships
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import {
|
|
15
|
+
* ProofPublisher,
|
|
16
|
+
* CardanoAnchorLinker,
|
|
17
|
+
* createProofPublisher,
|
|
18
|
+
* createCardanoAnchorLinker,
|
|
19
|
+
* } from "@fluxpointstudios/orynq-sdk-midnight-prover";
|
|
20
|
+
*
|
|
21
|
+
* const publisher = createProofPublisher({ maxRetries: 3 });
|
|
22
|
+
* const linker = createCardanoAnchorLinker({ debug: true });
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* Related files:
|
|
26
|
+
* - proof-publication.ts: Proof publishing to Midnight
|
|
27
|
+
* - cardano-anchor-link.ts: Cross-chain linking utilities
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
// =============================================================================
|
|
31
|
+
// PROOF PUBLICATION
|
|
32
|
+
// =============================================================================
|
|
33
|
+
|
|
34
|
+
export type {
|
|
35
|
+
ProofStatus,
|
|
36
|
+
ProofStatusInfo,
|
|
37
|
+
ProofPublisherOptions,
|
|
38
|
+
} from "./proof-publication.js";
|
|
39
|
+
|
|
40
|
+
export {
|
|
41
|
+
ProofPublisher,
|
|
42
|
+
createProofPublisher,
|
|
43
|
+
} from "./proof-publication.js";
|
|
44
|
+
|
|
45
|
+
// =============================================================================
|
|
46
|
+
// CROSS-CHAIN LINKING
|
|
47
|
+
// =============================================================================
|
|
48
|
+
|
|
49
|
+
export type {
|
|
50
|
+
CrossChainLink,
|
|
51
|
+
LinkVerificationResult,
|
|
52
|
+
CardanoAnchorLinkerOptions,
|
|
53
|
+
} from "./cardano-anchor-link.js";
|
|
54
|
+
|
|
55
|
+
export {
|
|
56
|
+
CardanoAnchorLinker,
|
|
57
|
+
createCardanoAnchorLinker,
|
|
58
|
+
} from "./cardano-anchor-link.js";
|
|
@@ -0,0 +1,557 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Proof publication to the Midnight network.
|
|
3
|
+
*
|
|
4
|
+
* Location: packages/midnight-prover/src/linking/proof-publication.ts
|
|
5
|
+
*
|
|
6
|
+
* Summary:
|
|
7
|
+
* This module implements the ProofPublisher class which handles submitting ZK proofs
|
|
8
|
+
* to the Midnight network and monitoring their publication status. It provides retry
|
|
9
|
+
* logic for resilient publication and confirmation waiting for transaction finality.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* - Used by the MidnightProver to publish proofs to the Midnight network
|
|
13
|
+
* - Integrates with proof-server-client.ts for network communication
|
|
14
|
+
* - Returns PublicationResult with midnightTxHash for cross-chain linking
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* import { ProofPublisher } from './proof-publication.js';
|
|
19
|
+
*
|
|
20
|
+
* const publisher = new ProofPublisher({ maxRetries: 3 });
|
|
21
|
+
* await publisher.connect(config);
|
|
22
|
+
*
|
|
23
|
+
* const result = await publisher.publish(proof);
|
|
24
|
+
* console.log('Published:', result.midnightTxHash);
|
|
25
|
+
*
|
|
26
|
+
* const confirmed = await publisher.waitForConfirmation(result.proofId);
|
|
27
|
+
* console.log('Confirmed:', confirmed);
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import type {
|
|
32
|
+
Proof,
|
|
33
|
+
PublicationResult,
|
|
34
|
+
ProofServerConfig,
|
|
35
|
+
AnyProof,
|
|
36
|
+
} from "../types.js";
|
|
37
|
+
|
|
38
|
+
import {
|
|
39
|
+
MidnightProverError,
|
|
40
|
+
MidnightProverException,
|
|
41
|
+
} from "../types.js";
|
|
42
|
+
|
|
43
|
+
import { sha256StringHex, canonicalize } from "@fluxpointstudios/orynq-sdk-core/utils";
|
|
44
|
+
|
|
45
|
+
// =============================================================================
|
|
46
|
+
// TYPES
|
|
47
|
+
// =============================================================================
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Status of a proof publication.
|
|
51
|
+
*/
|
|
52
|
+
export type ProofStatus =
|
|
53
|
+
| "pending" // Submitted but not yet confirmed
|
|
54
|
+
| "confirmed" // Included in a block
|
|
55
|
+
| "failed" // Transaction failed
|
|
56
|
+
| "not_found"; // Proof not found on network
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Detailed status information for a proof.
|
|
60
|
+
*/
|
|
61
|
+
export interface ProofStatusInfo {
|
|
62
|
+
status: ProofStatus;
|
|
63
|
+
proofId: string;
|
|
64
|
+
midnightTxHash: string | undefined;
|
|
65
|
+
blockNumber: number | undefined;
|
|
66
|
+
confirmations: number;
|
|
67
|
+
timestamp: string | undefined;
|
|
68
|
+
error: string | undefined;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Options for the ProofPublisher.
|
|
73
|
+
*/
|
|
74
|
+
export interface ProofPublisherOptions {
|
|
75
|
+
/**
|
|
76
|
+
* Maximum number of retry attempts for publication.
|
|
77
|
+
* Default: 3
|
|
78
|
+
*/
|
|
79
|
+
maxRetries?: number;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Base delay between retries in milliseconds (exponential backoff).
|
|
83
|
+
* Default: 1000
|
|
84
|
+
*/
|
|
85
|
+
retryDelayMs?: number;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Maximum delay between retries in milliseconds.
|
|
89
|
+
* Default: 30000
|
|
90
|
+
*/
|
|
91
|
+
maxRetryDelayMs?: number;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Default timeout for confirmation waiting in milliseconds.
|
|
95
|
+
* Default: 300000 (5 minutes)
|
|
96
|
+
*/
|
|
97
|
+
defaultConfirmationTimeoutMs?: number;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Polling interval for status checks in milliseconds.
|
|
101
|
+
* Default: 5000
|
|
102
|
+
*/
|
|
103
|
+
pollIntervalMs?: number;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Enable debug logging.
|
|
107
|
+
*/
|
|
108
|
+
debug?: boolean;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Domain separation prefixes for proof publication.
|
|
113
|
+
*/
|
|
114
|
+
const PUBLICATION_DOMAIN_PREFIXES = {
|
|
115
|
+
txHash: "poi-midnight:tx:v1|",
|
|
116
|
+
proofId: "poi-midnight:proof:v1|",
|
|
117
|
+
} as const;
|
|
118
|
+
|
|
119
|
+
// =============================================================================
|
|
120
|
+
// PROOF PUBLISHER
|
|
121
|
+
// =============================================================================
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* ProofPublisher handles submitting ZK proofs to the Midnight network.
|
|
125
|
+
*
|
|
126
|
+
* This class provides:
|
|
127
|
+
* - Resilient proof publication with retry logic
|
|
128
|
+
* - Status monitoring for submitted proofs
|
|
129
|
+
* - Confirmation waiting with timeout support
|
|
130
|
+
*
|
|
131
|
+
* Current implementation is a mock that simulates network interaction.
|
|
132
|
+
* Real Midnight integration will be added when the network SDK is available.
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```typescript
|
|
136
|
+
* const publisher = new ProofPublisher({ maxRetries: 3, debug: true });
|
|
137
|
+
* await publisher.connect(config);
|
|
138
|
+
*
|
|
139
|
+
* const result = await publisher.publish(hashChainProof);
|
|
140
|
+
* console.log('Transaction:', result.midnightTxHash);
|
|
141
|
+
*
|
|
142
|
+
* // Wait for confirmation
|
|
143
|
+
* const confirmed = await publisher.waitForConfirmation(result.proofId, 60000);
|
|
144
|
+
* if (confirmed) {
|
|
145
|
+
* console.log('Proof confirmed on Midnight network');
|
|
146
|
+
* }
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
export class ProofPublisher {
|
|
150
|
+
private readonly options: Required<ProofPublisherOptions>;
|
|
151
|
+
private config: ProofServerConfig | undefined;
|
|
152
|
+
private connected = false;
|
|
153
|
+
|
|
154
|
+
// Mock storage for simulated proofs (would be replaced with network state)
|
|
155
|
+
private readonly publishedProofs = new Map<string, {
|
|
156
|
+
result: PublicationResult;
|
|
157
|
+
status: ProofStatus;
|
|
158
|
+
confirmations: number;
|
|
159
|
+
submittedAt: number;
|
|
160
|
+
}>();
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Create a new ProofPublisher instance.
|
|
164
|
+
*
|
|
165
|
+
* @param options - Configuration options
|
|
166
|
+
*/
|
|
167
|
+
constructor(options: ProofPublisherOptions = {}) {
|
|
168
|
+
this.options = {
|
|
169
|
+
maxRetries: options.maxRetries ?? 3,
|
|
170
|
+
retryDelayMs: options.retryDelayMs ?? 1000,
|
|
171
|
+
maxRetryDelayMs: options.maxRetryDelayMs ?? 30000,
|
|
172
|
+
defaultConfirmationTimeoutMs: options.defaultConfirmationTimeoutMs ?? 300000,
|
|
173
|
+
pollIntervalMs: options.pollIntervalMs ?? 5000,
|
|
174
|
+
debug: options.debug ?? false,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Connect to the Midnight network.
|
|
180
|
+
*
|
|
181
|
+
* @param config - Proof server configuration
|
|
182
|
+
* @throws MidnightProverException on connection failure
|
|
183
|
+
*/
|
|
184
|
+
async connect(config: ProofServerConfig): Promise<void> {
|
|
185
|
+
this.debug("Connecting to Midnight network...");
|
|
186
|
+
|
|
187
|
+
try {
|
|
188
|
+
// Validate configuration
|
|
189
|
+
if (!config.proofServerUrl) {
|
|
190
|
+
throw new MidnightProverException(
|
|
191
|
+
MidnightProverError.INVALID_INPUT,
|
|
192
|
+
"Proof server URL is required"
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Mock connection - in production, this would establish network connection
|
|
197
|
+
await this.simulateNetworkDelay(50);
|
|
198
|
+
|
|
199
|
+
this.config = config;
|
|
200
|
+
this.connected = true;
|
|
201
|
+
|
|
202
|
+
this.debug(`Connected to ${config.proofServerUrl}`);
|
|
203
|
+
} catch (error) {
|
|
204
|
+
if (error instanceof MidnightProverException) {
|
|
205
|
+
throw error;
|
|
206
|
+
}
|
|
207
|
+
throw new MidnightProverException(
|
|
208
|
+
MidnightProverError.CONNECTION_FAILED,
|
|
209
|
+
`Failed to connect to Midnight network: ${String(error)}`,
|
|
210
|
+
error instanceof Error ? error : undefined
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Disconnect from the Midnight network.
|
|
217
|
+
*/
|
|
218
|
+
async disconnect(): Promise<void> {
|
|
219
|
+
if (this.connected) {
|
|
220
|
+
this.debug("Disconnecting from Midnight network...");
|
|
221
|
+
await this.simulateNetworkDelay(20);
|
|
222
|
+
this.connected = false;
|
|
223
|
+
this.config = undefined;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Check if connected to the network.
|
|
229
|
+
*/
|
|
230
|
+
isConnected(): boolean {
|
|
231
|
+
return this.connected;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Get the current configuration.
|
|
236
|
+
*/
|
|
237
|
+
getConfig(): ProofServerConfig | undefined {
|
|
238
|
+
return this.config;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Publish a proof to the Midnight network.
|
|
243
|
+
*
|
|
244
|
+
* This method:
|
|
245
|
+
* 1. Validates the proof structure
|
|
246
|
+
* 2. Serializes the proof for transmission
|
|
247
|
+
* 3. Submits to the network with retry logic
|
|
248
|
+
* 4. Returns the publication result with transaction hash
|
|
249
|
+
*
|
|
250
|
+
* @param proof - The proof to publish
|
|
251
|
+
* @returns Publication result with Midnight transaction hash
|
|
252
|
+
* @throws MidnightProverException on failure after all retries
|
|
253
|
+
*/
|
|
254
|
+
async publish(proof: Proof): Promise<PublicationResult> {
|
|
255
|
+
this.ensureConnected();
|
|
256
|
+
|
|
257
|
+
this.debug(`Publishing proof: ${proof.proofId}`);
|
|
258
|
+
|
|
259
|
+
// Validate proof
|
|
260
|
+
this.validateProof(proof);
|
|
261
|
+
|
|
262
|
+
// Extract cardano anchor tx hash from proof if it has public inputs
|
|
263
|
+
const cardanoAnchorTxHash = this.extractCardanoAnchorTxHash(proof as AnyProof);
|
|
264
|
+
|
|
265
|
+
let lastError: Error | undefined;
|
|
266
|
+
|
|
267
|
+
for (let attempt = 0; attempt < this.options.maxRetries; attempt++) {
|
|
268
|
+
try {
|
|
269
|
+
const result = await this.attemptPublish(proof, cardanoAnchorTxHash, attempt);
|
|
270
|
+
return result;
|
|
271
|
+
} catch (error) {
|
|
272
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
273
|
+
this.debug(`Publication attempt ${attempt + 1} failed: ${lastError.message}`);
|
|
274
|
+
|
|
275
|
+
if (attempt < this.options.maxRetries - 1) {
|
|
276
|
+
const delay = this.calculateRetryDelay(attempt);
|
|
277
|
+
this.debug(`Retrying in ${delay}ms...`);
|
|
278
|
+
await this.delay(delay);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
throw new MidnightProverException(
|
|
284
|
+
MidnightProverError.PUBLICATION_FAILED,
|
|
285
|
+
`Failed to publish proof after ${this.options.maxRetries} attempts`,
|
|
286
|
+
lastError
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Get the status of a published proof.
|
|
292
|
+
*
|
|
293
|
+
* @param proofId - Unique proof identifier
|
|
294
|
+
* @returns Promise resolving to the proof status
|
|
295
|
+
*/
|
|
296
|
+
async getProofStatus(proofId: string): Promise<ProofStatusInfo> {
|
|
297
|
+
this.ensureConnected();
|
|
298
|
+
|
|
299
|
+
await this.simulateNetworkDelay(30);
|
|
300
|
+
|
|
301
|
+
const record = this.publishedProofs.get(proofId);
|
|
302
|
+
if (!record) {
|
|
303
|
+
return {
|
|
304
|
+
status: "not_found",
|
|
305
|
+
proofId,
|
|
306
|
+
midnightTxHash: undefined,
|
|
307
|
+
blockNumber: undefined,
|
|
308
|
+
confirmations: 0,
|
|
309
|
+
timestamp: undefined,
|
|
310
|
+
error: undefined,
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Simulate confirmation progression over time
|
|
315
|
+
const elapsed = Date.now() - record.submittedAt;
|
|
316
|
+
if (record.status === "pending" && elapsed > 10000) {
|
|
317
|
+
record.status = "confirmed";
|
|
318
|
+
record.confirmations = Math.min(Math.floor(elapsed / 5000), 10);
|
|
319
|
+
} else if (record.status === "confirmed") {
|
|
320
|
+
record.confirmations = Math.min(Math.floor(elapsed / 5000), 100);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return {
|
|
324
|
+
status: record.status,
|
|
325
|
+
proofId,
|
|
326
|
+
midnightTxHash: record.result.midnightTxHash,
|
|
327
|
+
blockNumber: record.result.blockNumber,
|
|
328
|
+
confirmations: record.confirmations,
|
|
329
|
+
timestamp: record.result.timestamp,
|
|
330
|
+
error: undefined,
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Wait for a proof to be confirmed on the network.
|
|
336
|
+
*
|
|
337
|
+
* @param proofId - Unique proof identifier
|
|
338
|
+
* @param timeoutMs - Maximum time to wait in milliseconds (default: 5 minutes)
|
|
339
|
+
* @returns Promise resolving to true if confirmed, false if timeout
|
|
340
|
+
*/
|
|
341
|
+
async waitForConfirmation(
|
|
342
|
+
proofId: string,
|
|
343
|
+
timeoutMs?: number
|
|
344
|
+
): Promise<boolean> {
|
|
345
|
+
this.ensureConnected();
|
|
346
|
+
|
|
347
|
+
const timeout = timeoutMs ?? this.options.defaultConfirmationTimeoutMs;
|
|
348
|
+
const startTime = Date.now();
|
|
349
|
+
|
|
350
|
+
this.debug(`Waiting for confirmation of proof ${proofId} (timeout: ${timeout}ms)`);
|
|
351
|
+
|
|
352
|
+
while (Date.now() - startTime < timeout) {
|
|
353
|
+
const status = await this.getProofStatus(proofId);
|
|
354
|
+
|
|
355
|
+
if (status.status === "confirmed") {
|
|
356
|
+
this.debug(`Proof ${proofId} confirmed with ${status.confirmations} confirmations`);
|
|
357
|
+
return true;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if (status.status === "failed") {
|
|
361
|
+
this.debug(`Proof ${proofId} failed: ${status.error ?? "unknown error"}`);
|
|
362
|
+
return false;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
if (status.status === "not_found") {
|
|
366
|
+
this.debug(`Proof ${proofId} not found on network`);
|
|
367
|
+
return false;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Wait before next poll
|
|
371
|
+
await this.delay(this.options.pollIntervalMs);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
this.debug(`Confirmation timeout for proof ${proofId}`);
|
|
375
|
+
return false;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Get the publication result for a proof.
|
|
380
|
+
*
|
|
381
|
+
* @param proofId - Unique proof identifier
|
|
382
|
+
* @returns The publication result if found, undefined otherwise
|
|
383
|
+
*/
|
|
384
|
+
getPublicationResult(proofId: string): PublicationResult | undefined {
|
|
385
|
+
return this.publishedProofs.get(proofId)?.result;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// ===========================================================================
|
|
389
|
+
// PRIVATE METHODS
|
|
390
|
+
// ===========================================================================
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Ensure connected before operations.
|
|
394
|
+
*/
|
|
395
|
+
private ensureConnected(): void {
|
|
396
|
+
if (!this.connected) {
|
|
397
|
+
throw new MidnightProverException(
|
|
398
|
+
MidnightProverError.CONNECTION_FAILED,
|
|
399
|
+
"Not connected to Midnight network. Call connect() first."
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Validate a proof before publication.
|
|
406
|
+
*/
|
|
407
|
+
private validateProof(proof: Proof): void {
|
|
408
|
+
if (!proof.proofId) {
|
|
409
|
+
throw new MidnightProverException(
|
|
410
|
+
MidnightProverError.INVALID_INPUT,
|
|
411
|
+
"Proof ID is required"
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (!proof.proof || proof.proof.length === 0) {
|
|
416
|
+
throw new MidnightProverException(
|
|
417
|
+
MidnightProverError.INVALID_PROOF_FORMAT,
|
|
418
|
+
"Proof data is empty"
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
if (!proof.proofType) {
|
|
423
|
+
throw new MidnightProverException(
|
|
424
|
+
MidnightProverError.INVALID_INPUT,
|
|
425
|
+
"Proof type is required"
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Extract Cardano anchor transaction hash from proof public inputs.
|
|
432
|
+
*/
|
|
433
|
+
private extractCardanoAnchorTxHash(proof: AnyProof): string {
|
|
434
|
+
// Type-safe access to publicInputs.cardanoAnchorTxHash
|
|
435
|
+
const anyProof = proof as { publicInputs?: { cardanoAnchorTxHash?: string } };
|
|
436
|
+
const txHash = anyProof.publicInputs?.cardanoAnchorTxHash;
|
|
437
|
+
|
|
438
|
+
if (!txHash) {
|
|
439
|
+
throw new MidnightProverException(
|
|
440
|
+
MidnightProverError.MISSING_REQUIRED_FIELD,
|
|
441
|
+
"Proof must have cardanoAnchorTxHash in public inputs for cross-chain linking"
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
return txHash;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Attempt to publish a proof (single attempt).
|
|
450
|
+
*/
|
|
451
|
+
private async attemptPublish(
|
|
452
|
+
proof: Proof,
|
|
453
|
+
cardanoAnchorTxHash: string,
|
|
454
|
+
_attempt: number
|
|
455
|
+
): Promise<PublicationResult> {
|
|
456
|
+
// Simulate network submission
|
|
457
|
+
await this.simulateNetworkDelay(100 + Math.random() * 100);
|
|
458
|
+
|
|
459
|
+
// Generate mock transaction hash
|
|
460
|
+
const txInputData = canonicalize({
|
|
461
|
+
proofId: proof.proofId,
|
|
462
|
+
proofType: proof.proofType,
|
|
463
|
+
proofHash: await this.hashProofBytes(proof.proof),
|
|
464
|
+
timestamp: new Date().toISOString(),
|
|
465
|
+
});
|
|
466
|
+
const midnightTxHash = await sha256StringHex(PUBLICATION_DOMAIN_PREFIXES.txHash + txInputData);
|
|
467
|
+
|
|
468
|
+
// Simulate occasional network failures (10% failure rate on first attempt only)
|
|
469
|
+
// This ensures retries work but doesn't cause flaky tests
|
|
470
|
+
if (Math.random() < 0.1 && _attempt === 0) {
|
|
471
|
+
throw new Error("Simulated network failure");
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
const result: PublicationResult = {
|
|
475
|
+
midnightTxHash,
|
|
476
|
+
proofId: proof.proofId,
|
|
477
|
+
timestamp: new Date().toISOString(),
|
|
478
|
+
cardanoAnchorTxHash,
|
|
479
|
+
blockNumber: Math.floor(100000 + Math.random() * 10000),
|
|
480
|
+
fee: BigInt(Math.floor(1000 + Math.random() * 500)),
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
// Store in mock registry
|
|
484
|
+
this.publishedProofs.set(proof.proofId, {
|
|
485
|
+
result,
|
|
486
|
+
status: "pending",
|
|
487
|
+
confirmations: 0,
|
|
488
|
+
submittedAt: Date.now(),
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
this.debug(`Proof published: ${midnightTxHash}`);
|
|
492
|
+
|
|
493
|
+
return result;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Hash proof bytes for transaction identification.
|
|
498
|
+
*/
|
|
499
|
+
private async hashProofBytes(proofBytes: Uint8Array): Promise<string> {
|
|
500
|
+
// Create a copy to ensure ArrayBuffer type compatibility
|
|
501
|
+
const buffer = new ArrayBuffer(proofBytes.length);
|
|
502
|
+
new Uint8Array(buffer).set(proofBytes);
|
|
503
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", buffer);
|
|
504
|
+
const hashArray = new Uint8Array(hashBuffer);
|
|
505
|
+
return Array.from(hashArray)
|
|
506
|
+
.map((b) => b.toString(16).padStart(2, "0"))
|
|
507
|
+
.join("");
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* Calculate retry delay with exponential backoff.
|
|
512
|
+
*/
|
|
513
|
+
private calculateRetryDelay(attempt: number): number {
|
|
514
|
+
const delay = this.options.retryDelayMs * Math.pow(2, attempt);
|
|
515
|
+
return Math.min(delay, this.options.maxRetryDelayMs);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* Simulate network delay for mock operations.
|
|
520
|
+
*/
|
|
521
|
+
private async simulateNetworkDelay(baseMs: number): Promise<void> {
|
|
522
|
+
const jitter = Math.random() * baseMs * 0.2;
|
|
523
|
+
await this.delay(baseMs + jitter);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* Delay helper.
|
|
528
|
+
*/
|
|
529
|
+
private delay(ms: number): Promise<void> {
|
|
530
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Debug logging helper.
|
|
535
|
+
*/
|
|
536
|
+
private debug(message: string): void {
|
|
537
|
+
if (this.options.debug) {
|
|
538
|
+
console.log(`[ProofPublisher] ${message}`);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// =============================================================================
|
|
544
|
+
// FACTORY FUNCTION
|
|
545
|
+
// =============================================================================
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Create a new ProofPublisher instance.
|
|
549
|
+
*
|
|
550
|
+
* @param options - Configuration options
|
|
551
|
+
* @returns New ProofPublisher instance
|
|
552
|
+
*/
|
|
553
|
+
export function createProofPublisher(
|
|
554
|
+
options?: ProofPublisherOptions
|
|
555
|
+
): ProofPublisher {
|
|
556
|
+
return new ProofPublisher(options);
|
|
557
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Midnight circuit utilities exports.
|
|
3
|
+
*
|
|
4
|
+
* Location: packages/midnight-prover/src/midnight/index.ts
|
|
5
|
+
*
|
|
6
|
+
* Summary:
|
|
7
|
+
* This file exports all Midnight-specific utilities for witness building
|
|
8
|
+
* and public input construction. These components prepare data for
|
|
9
|
+
* submission to Midnight's Compact circuits.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import {
|
|
14
|
+
* buildHashChainWitness,
|
|
15
|
+
* buildPublicInputs,
|
|
16
|
+
* serializeWitness,
|
|
17
|
+
* } from "@fluxpointstudios/orynq-sdk-midnight-prover";
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* Related files:
|
|
21
|
+
* - witness-builder.ts: Converts trace events to circuit-compatible witnesses
|
|
22
|
+
* - public-inputs.ts: Builds and serializes public inputs for proofs
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
// =============================================================================
|
|
26
|
+
// WITNESS BUILDER
|
|
27
|
+
// =============================================================================
|
|
28
|
+
|
|
29
|
+
export type {
|
|
30
|
+
EventWitness,
|
|
31
|
+
HashChainWitness,
|
|
32
|
+
} from "./witness-builder.js";
|
|
33
|
+
|
|
34
|
+
export {
|
|
35
|
+
buildHashChainWitness,
|
|
36
|
+
serializeWitness,
|
|
37
|
+
computeWitnessSize,
|
|
38
|
+
validateWitness,
|
|
39
|
+
} from "./witness-builder.js";
|
|
40
|
+
|
|
41
|
+
// =============================================================================
|
|
42
|
+
// PUBLIC INPUTS
|
|
43
|
+
// =============================================================================
|
|
44
|
+
|
|
45
|
+
export type {
|
|
46
|
+
HashChainPublicInputData,
|
|
47
|
+
PolicyPublicInputData,
|
|
48
|
+
AttestationPublicInputData,
|
|
49
|
+
DisclosurePublicInputData,
|
|
50
|
+
InferencePublicInputData,
|
|
51
|
+
AnyPublicInputData,
|
|
52
|
+
} from "./public-inputs.js";
|
|
53
|
+
|
|
54
|
+
export {
|
|
55
|
+
buildPublicInputs,
|
|
56
|
+
serializePublicInputs,
|
|
57
|
+
hashPublicInputs,
|
|
58
|
+
} from "./public-inputs.js";
|
|
59
|
+
|
|
60
|
+
// =============================================================================
|
|
61
|
+
// PROOF SERVER CLIENT
|
|
62
|
+
// =============================================================================
|
|
63
|
+
|
|
64
|
+
export type {
|
|
65
|
+
ProofResult,
|
|
66
|
+
CircuitInfo,
|
|
67
|
+
ProofServerClientOptions,
|
|
68
|
+
} from "./proof-server-client.js";
|
|
69
|
+
|
|
70
|
+
export {
|
|
71
|
+
ProofServerClient,
|
|
72
|
+
createProofServerClient,
|
|
73
|
+
} from "./proof-server-client.js";
|