@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,595 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Midnight proof server client for ZK proof generation.
|
|
3
|
+
*
|
|
4
|
+
* Location: packages/midnight-prover/src/midnight/proof-server-client.ts
|
|
5
|
+
*
|
|
6
|
+
* Summary:
|
|
7
|
+
* This module implements the ProofServerClient class which handles communication
|
|
8
|
+
* with the Midnight proof server for ZK proof generation. It manages connection
|
|
9
|
+
* lifecycle, proof submission, and result retrieval.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* - Used by the DefaultMidnightProver to generate proofs
|
|
13
|
+
* - Handles connection management and request/response serialization
|
|
14
|
+
* - Current implementation is a mock for testing; real Midnight integration TBD
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* import { ProofServerClient } from './proof-server-client.js';
|
|
19
|
+
*
|
|
20
|
+
* const client = new ProofServerClient();
|
|
21
|
+
* await client.connect(config);
|
|
22
|
+
*
|
|
23
|
+
* const result = await client.submitProof('hash-chain', witness, publicInputs);
|
|
24
|
+
* console.log('Proof generated:', result.proofId);
|
|
25
|
+
*
|
|
26
|
+
* await client.disconnect();
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
import type { ProofServerConfig, ProofType } from "../types.js";
|
|
31
|
+
|
|
32
|
+
import {
|
|
33
|
+
MidnightProverError,
|
|
34
|
+
MidnightProverException,
|
|
35
|
+
} from "../types.js";
|
|
36
|
+
|
|
37
|
+
import { sha256StringHex, canonicalize } from "@fluxpointstudios/orynq-sdk-core/utils";
|
|
38
|
+
|
|
39
|
+
// =============================================================================
|
|
40
|
+
// TYPES
|
|
41
|
+
// =============================================================================
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Result of proof generation from the server.
|
|
45
|
+
*/
|
|
46
|
+
export interface ProofResult {
|
|
47
|
+
/**
|
|
48
|
+
* Unique proof identifier.
|
|
49
|
+
*/
|
|
50
|
+
proofId: string;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The generated proof bytes.
|
|
54
|
+
*/
|
|
55
|
+
proof: Uint8Array;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Time taken to generate the proof in milliseconds.
|
|
59
|
+
*/
|
|
60
|
+
provingTimeMs: number;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Size of the proof in bytes.
|
|
64
|
+
*/
|
|
65
|
+
proofSizeBytes: number;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Circuit name used for proof generation.
|
|
69
|
+
*/
|
|
70
|
+
circuit: string;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Server-side metadata.
|
|
74
|
+
*/
|
|
75
|
+
serverMetadata: {
|
|
76
|
+
serverId: string;
|
|
77
|
+
circuitVersion: string;
|
|
78
|
+
computeTimeMs: number;
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Circuit information from the server.
|
|
84
|
+
*/
|
|
85
|
+
export interface CircuitInfo {
|
|
86
|
+
name: string;
|
|
87
|
+
version: string;
|
|
88
|
+
constraintCount: number;
|
|
89
|
+
publicInputCount: number;
|
|
90
|
+
available: boolean;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Options for the ProofServerClient.
|
|
95
|
+
*/
|
|
96
|
+
export interface ProofServerClientOptions {
|
|
97
|
+
/**
|
|
98
|
+
* Enable debug logging.
|
|
99
|
+
*/
|
|
100
|
+
debug?: boolean;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Simulated proof generation time in milliseconds.
|
|
104
|
+
* Default: 50ms for fast testing.
|
|
105
|
+
*/
|
|
106
|
+
simulatedProvingTimeMs?: number;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Circuit names for different proof types.
|
|
111
|
+
*/
|
|
112
|
+
const CIRCUIT_NAMES: Record<ProofType, string> = {
|
|
113
|
+
"hash-chain": "poi_hash_chain_v1",
|
|
114
|
+
"policy-compliance": "poi_policy_compliance_v1",
|
|
115
|
+
"attestation-valid": "poi_attestation_v1",
|
|
116
|
+
"selective-disclosure": "poi_disclosure_v1",
|
|
117
|
+
"zkml-inference": "poi_inference_v1",
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
// =============================================================================
|
|
121
|
+
// PROOF SERVER CLIENT
|
|
122
|
+
// =============================================================================
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* ProofServerClient handles communication with the Midnight proof server.
|
|
126
|
+
*
|
|
127
|
+
* This class provides:
|
|
128
|
+
* - Connection management to the proof server
|
|
129
|
+
* - Proof submission with witness and public inputs
|
|
130
|
+
* - Circuit information queries
|
|
131
|
+
*
|
|
132
|
+
* Current implementation is a mock that simulates proof server behavior.
|
|
133
|
+
* Real Midnight integration will be added when the Compact runtime is available.
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```typescript
|
|
137
|
+
* const client = new ProofServerClient({ debug: true });
|
|
138
|
+
*
|
|
139
|
+
* await client.connect({
|
|
140
|
+
* proofServerUrl: 'https://proof.midnight.network',
|
|
141
|
+
* timeout: 300000,
|
|
142
|
+
* retries: 3,
|
|
143
|
+
* });
|
|
144
|
+
*
|
|
145
|
+
* const result = await client.submitProof('hash-chain', witness, publicInputs);
|
|
146
|
+
* console.log('Generated proof:', result.proofId);
|
|
147
|
+
*
|
|
148
|
+
* await client.disconnect();
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
export class ProofServerClient {
|
|
152
|
+
private readonly options: Required<ProofServerClientOptions>;
|
|
153
|
+
private config: ProofServerConfig | undefined;
|
|
154
|
+
private connected = false;
|
|
155
|
+
private serverId: string | undefined;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Create a new ProofServerClient instance.
|
|
159
|
+
*
|
|
160
|
+
* @param options - Configuration options
|
|
161
|
+
*/
|
|
162
|
+
constructor(options: ProofServerClientOptions = {}) {
|
|
163
|
+
this.options = {
|
|
164
|
+
debug: options.debug ?? false,
|
|
165
|
+
simulatedProvingTimeMs: options.simulatedProvingTimeMs ?? 50,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Connect to the Midnight proof server.
|
|
171
|
+
*
|
|
172
|
+
* @param config - Proof server configuration
|
|
173
|
+
* @throws MidnightProverException on connection failure
|
|
174
|
+
*/
|
|
175
|
+
async connect(config: ProofServerConfig): Promise<void> {
|
|
176
|
+
this.debug(`Connecting to proof server at ${config.proofServerUrl}...`);
|
|
177
|
+
|
|
178
|
+
try {
|
|
179
|
+
// Validate configuration
|
|
180
|
+
this.validateConfig(config);
|
|
181
|
+
|
|
182
|
+
// Simulate connection establishment
|
|
183
|
+
await this.simulateNetworkDelay(30);
|
|
184
|
+
|
|
185
|
+
// In production, this would establish a WebSocket or HTTP connection
|
|
186
|
+
// and perform any necessary handshaking/authentication
|
|
187
|
+
if (config.apiKey) {
|
|
188
|
+
this.debug("Authenticating with API key...");
|
|
189
|
+
await this.simulateNetworkDelay(20);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Generate a mock server ID
|
|
193
|
+
this.serverId = `server-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
194
|
+
|
|
195
|
+
this.config = config;
|
|
196
|
+
this.connected = true;
|
|
197
|
+
|
|
198
|
+
this.debug(`Connected to proof server (serverId: ${this.serverId})`);
|
|
199
|
+
} catch (error) {
|
|
200
|
+
if (error instanceof MidnightProverException) {
|
|
201
|
+
throw error;
|
|
202
|
+
}
|
|
203
|
+
throw new MidnightProverException(
|
|
204
|
+
MidnightProverError.CONNECTION_FAILED,
|
|
205
|
+
`Failed to connect to proof server: ${String(error)}`,
|
|
206
|
+
error instanceof Error ? error : undefined
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Disconnect from the proof server.
|
|
213
|
+
*/
|
|
214
|
+
async disconnect(): Promise<void> {
|
|
215
|
+
if (this.connected) {
|
|
216
|
+
this.debug("Disconnecting from proof server...");
|
|
217
|
+
await this.simulateNetworkDelay(10);
|
|
218
|
+
this.connected = false;
|
|
219
|
+
this.config = undefined;
|
|
220
|
+
this.serverId = undefined;
|
|
221
|
+
this.debug("Disconnected");
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Check if connected to the proof server.
|
|
227
|
+
*/
|
|
228
|
+
isConnected(): boolean {
|
|
229
|
+
return this.connected;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Get the current configuration.
|
|
234
|
+
*/
|
|
235
|
+
getConfig(): ProofServerConfig | undefined {
|
|
236
|
+
return this.config;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Submit a proof request to the server.
|
|
241
|
+
*
|
|
242
|
+
* This method:
|
|
243
|
+
* 1. Validates the circuit and inputs
|
|
244
|
+
* 2. Serializes the witness and public inputs
|
|
245
|
+
* 3. Submits to the proof server
|
|
246
|
+
* 4. Returns the generated proof
|
|
247
|
+
*
|
|
248
|
+
* @param circuit - Circuit name (e.g., "hash-chain", "policy-compliance")
|
|
249
|
+
* @param witness - Private witness data for the proof
|
|
250
|
+
* @param publicInputs - Public inputs for the proof
|
|
251
|
+
* @returns Promise resolving to the proof result
|
|
252
|
+
* @throws MidnightProverException on failure
|
|
253
|
+
*/
|
|
254
|
+
async submitProof(
|
|
255
|
+
circuit: string,
|
|
256
|
+
witness: unknown,
|
|
257
|
+
publicInputs: unknown
|
|
258
|
+
): Promise<ProofResult> {
|
|
259
|
+
this.ensureConnected();
|
|
260
|
+
|
|
261
|
+
const circuitName = this.resolveCircuitName(circuit);
|
|
262
|
+
this.debug(`Submitting proof request for circuit: ${circuitName}`);
|
|
263
|
+
|
|
264
|
+
const startTime = Date.now();
|
|
265
|
+
|
|
266
|
+
try {
|
|
267
|
+
// Validate circuit exists
|
|
268
|
+
const circuitInfo = await this.getCircuitInfo(circuitName);
|
|
269
|
+
if (!circuitInfo.available) {
|
|
270
|
+
throw new MidnightProverException(
|
|
271
|
+
MidnightProverError.CIRCUIT_NOT_FOUND,
|
|
272
|
+
`Circuit '${circuitName}' is not available`
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Serialize inputs
|
|
277
|
+
const serializedWitness = this.serializeInput(witness);
|
|
278
|
+
const serializedPublicInputs = this.serializeInput(publicInputs);
|
|
279
|
+
|
|
280
|
+
this.debug(`Witness size: ${serializedWitness.length} bytes`);
|
|
281
|
+
this.debug(`Public inputs size: ${serializedPublicInputs.length} bytes`);
|
|
282
|
+
|
|
283
|
+
// Simulate proof generation
|
|
284
|
+
await this.simulateProofGeneration();
|
|
285
|
+
|
|
286
|
+
// Generate mock proof
|
|
287
|
+
const proof = await this.generateMockProof(
|
|
288
|
+
circuitName,
|
|
289
|
+
serializedWitness,
|
|
290
|
+
serializedPublicInputs
|
|
291
|
+
);
|
|
292
|
+
|
|
293
|
+
const provingTimeMs = Date.now() - startTime;
|
|
294
|
+
|
|
295
|
+
// Generate proof ID
|
|
296
|
+
const proofId = await this.generateProofId(proof);
|
|
297
|
+
|
|
298
|
+
const result: ProofResult = {
|
|
299
|
+
proofId,
|
|
300
|
+
proof,
|
|
301
|
+
provingTimeMs,
|
|
302
|
+
proofSizeBytes: proof.length,
|
|
303
|
+
circuit: circuitName,
|
|
304
|
+
serverMetadata: {
|
|
305
|
+
serverId: this.serverId ?? "unknown",
|
|
306
|
+
circuitVersion: circuitInfo.version,
|
|
307
|
+
computeTimeMs: this.options.simulatedProvingTimeMs,
|
|
308
|
+
},
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
this.debug(`Proof generated: ${proofId} (${provingTimeMs}ms)`);
|
|
312
|
+
|
|
313
|
+
return result;
|
|
314
|
+
} catch (error) {
|
|
315
|
+
if (error instanceof MidnightProverException) {
|
|
316
|
+
throw error;
|
|
317
|
+
}
|
|
318
|
+
throw new MidnightProverException(
|
|
319
|
+
MidnightProverError.PROOF_GENERATION_FAILED,
|
|
320
|
+
`Proof generation failed: ${String(error)}`,
|
|
321
|
+
error instanceof Error ? error : undefined
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Get information about a circuit.
|
|
328
|
+
*
|
|
329
|
+
* @param circuitName - Name of the circuit
|
|
330
|
+
* @returns Circuit information
|
|
331
|
+
*/
|
|
332
|
+
async getCircuitInfo(circuitName: string): Promise<CircuitInfo> {
|
|
333
|
+
this.ensureConnected();
|
|
334
|
+
|
|
335
|
+
await this.simulateNetworkDelay(20);
|
|
336
|
+
|
|
337
|
+
// Mock circuit information
|
|
338
|
+
const baseCircuitInfo: Omit<CircuitInfo, "name"> = {
|
|
339
|
+
version: "1.0.0",
|
|
340
|
+
constraintCount: 1000000,
|
|
341
|
+
publicInputCount: 10,
|
|
342
|
+
available: true,
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
// Circuit-specific information
|
|
346
|
+
const circuitConfigs: Record<string, Partial<CircuitInfo>> = {
|
|
347
|
+
poi_hash_chain_v1: {
|
|
348
|
+
constraintCount: 500000,
|
|
349
|
+
publicInputCount: 3,
|
|
350
|
+
},
|
|
351
|
+
poi_policy_compliance_v1: {
|
|
352
|
+
constraintCount: 750000,
|
|
353
|
+
publicInputCount: 5,
|
|
354
|
+
},
|
|
355
|
+
poi_attestation_v1: {
|
|
356
|
+
constraintCount: 600000,
|
|
357
|
+
publicInputCount: 4,
|
|
358
|
+
},
|
|
359
|
+
poi_disclosure_v1: {
|
|
360
|
+
constraintCount: 400000,
|
|
361
|
+
publicInputCount: 3,
|
|
362
|
+
},
|
|
363
|
+
poi_inference_v1: {
|
|
364
|
+
constraintCount: 10000000, // Very large for zkML
|
|
365
|
+
publicInputCount: 5,
|
|
366
|
+
available: false, // Mark as unavailable by default
|
|
367
|
+
},
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
const specificConfig = circuitConfigs[circuitName] ?? {};
|
|
371
|
+
|
|
372
|
+
return {
|
|
373
|
+
name: circuitName,
|
|
374
|
+
...baseCircuitInfo,
|
|
375
|
+
...specificConfig,
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* List all available circuits.
|
|
381
|
+
*
|
|
382
|
+
* @returns Array of circuit names
|
|
383
|
+
*/
|
|
384
|
+
async listCircuits(): Promise<string[]> {
|
|
385
|
+
this.ensureConnected();
|
|
386
|
+
|
|
387
|
+
await this.simulateNetworkDelay(15);
|
|
388
|
+
|
|
389
|
+
return Object.values(CIRCUIT_NAMES);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Check if a circuit is available.
|
|
394
|
+
*
|
|
395
|
+
* @param circuit - Circuit name or proof type
|
|
396
|
+
* @returns True if the circuit is available
|
|
397
|
+
*/
|
|
398
|
+
async isCircuitAvailable(circuit: string): Promise<boolean> {
|
|
399
|
+
const circuitName = this.resolveCircuitName(circuit);
|
|
400
|
+
const info = await this.getCircuitInfo(circuitName);
|
|
401
|
+
return info.available;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// ===========================================================================
|
|
405
|
+
// PRIVATE METHODS
|
|
406
|
+
// ===========================================================================
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Ensure connected before operations.
|
|
410
|
+
*/
|
|
411
|
+
private ensureConnected(): void {
|
|
412
|
+
if (!this.connected) {
|
|
413
|
+
throw new MidnightProverException(
|
|
414
|
+
MidnightProverError.CONNECTION_FAILED,
|
|
415
|
+
"Not connected to proof server. Call connect() first."
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Validate server configuration.
|
|
422
|
+
*/
|
|
423
|
+
private validateConfig(config: ProofServerConfig): void {
|
|
424
|
+
if (!config.proofServerUrl) {
|
|
425
|
+
throw new MidnightProverException(
|
|
426
|
+
MidnightProverError.INVALID_INPUT,
|
|
427
|
+
"Proof server URL is required"
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (config.timeout !== undefined && config.timeout <= 0) {
|
|
432
|
+
throw new MidnightProverException(
|
|
433
|
+
MidnightProverError.INVALID_INPUT,
|
|
434
|
+
"Timeout must be positive"
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (config.retries !== undefined && config.retries < 0) {
|
|
439
|
+
throw new MidnightProverException(
|
|
440
|
+
MidnightProverError.INVALID_INPUT,
|
|
441
|
+
"Retries must be non-negative"
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Resolve circuit name from proof type or direct name.
|
|
448
|
+
*/
|
|
449
|
+
private resolveCircuitName(circuit: string): string {
|
|
450
|
+
// Check if it's a proof type
|
|
451
|
+
const proofType = circuit as ProofType;
|
|
452
|
+
if (proofType in CIRCUIT_NAMES) {
|
|
453
|
+
return CIRCUIT_NAMES[proofType];
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// Assume it's already a circuit name
|
|
457
|
+
return circuit;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Serialize input data for transmission.
|
|
462
|
+
*/
|
|
463
|
+
private serializeInput(input: unknown): Uint8Array {
|
|
464
|
+
const jsonString = canonicalize(input);
|
|
465
|
+
return new TextEncoder().encode(jsonString);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Simulate proof generation delay.
|
|
470
|
+
*/
|
|
471
|
+
private async simulateProofGeneration(): Promise<void> {
|
|
472
|
+
// Add some variance to simulate real proof generation
|
|
473
|
+
const variance = Math.random() * 0.2 - 0.1; // +/- 10%
|
|
474
|
+
const delay = this.options.simulatedProvingTimeMs * (1 + variance);
|
|
475
|
+
await this.delay(delay);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Generate a mock proof.
|
|
480
|
+
*/
|
|
481
|
+
private async generateMockProof(
|
|
482
|
+
circuitName: string,
|
|
483
|
+
witness: Uint8Array,
|
|
484
|
+
publicInputs: Uint8Array
|
|
485
|
+
): Promise<Uint8Array> {
|
|
486
|
+
// Create a deterministic mock proof based on inputs
|
|
487
|
+
const witnessHash = await this.hashBytes(witness);
|
|
488
|
+
const publicInputsHash = await this.hashBytes(publicInputs);
|
|
489
|
+
|
|
490
|
+
// Mock proof structure:
|
|
491
|
+
// - Magic header (16 bytes): "MOCK-MIDNIGHT-V1"
|
|
492
|
+
// - Circuit name hash (32 bytes)
|
|
493
|
+
// - Witness commitment (32 bytes)
|
|
494
|
+
// - Public inputs commitment (32 bytes)
|
|
495
|
+
// - Random padding (144 bytes)
|
|
496
|
+
// Total: 256 bytes
|
|
497
|
+
|
|
498
|
+
const proof = new Uint8Array(256);
|
|
499
|
+
const header = new TextEncoder().encode("MOCK-MIDNIGHT-V1");
|
|
500
|
+
proof.set(header, 0);
|
|
501
|
+
|
|
502
|
+
// Circuit name hash
|
|
503
|
+
const circuitHash = await sha256StringHex(circuitName);
|
|
504
|
+
const circuitHashBytes = this.hexToBytes(circuitHash);
|
|
505
|
+
proof.set(circuitHashBytes, 16);
|
|
506
|
+
|
|
507
|
+
// Witness commitment
|
|
508
|
+
const witnessBytes = this.hexToBytes(witnessHash);
|
|
509
|
+
proof.set(witnessBytes, 48);
|
|
510
|
+
|
|
511
|
+
// Public inputs commitment
|
|
512
|
+
const publicInputsBytes = this.hexToBytes(publicInputsHash);
|
|
513
|
+
proof.set(publicInputsBytes, 80);
|
|
514
|
+
|
|
515
|
+
// Random padding
|
|
516
|
+
const randomPadding = new Uint8Array(144);
|
|
517
|
+
crypto.getRandomValues(randomPadding);
|
|
518
|
+
proof.set(randomPadding, 112);
|
|
519
|
+
|
|
520
|
+
return proof;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* Generate a proof ID.
|
|
525
|
+
*/
|
|
526
|
+
private async generateProofId(proof: Uint8Array): Promise<string> {
|
|
527
|
+
const hash = await this.hashBytes(proof);
|
|
528
|
+
return `proof-${hash.slice(0, 16)}`;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* Hash bytes to hex string.
|
|
533
|
+
*/
|
|
534
|
+
private async hashBytes(data: Uint8Array): Promise<string> {
|
|
535
|
+
// Create a copy to ensure ArrayBuffer type compatibility
|
|
536
|
+
const buffer = new ArrayBuffer(data.length);
|
|
537
|
+
new Uint8Array(buffer).set(data);
|
|
538
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", buffer);
|
|
539
|
+
const hashArray = new Uint8Array(hashBuffer);
|
|
540
|
+
return Array.from(hashArray)
|
|
541
|
+
.map((b) => b.toString(16).padStart(2, "0"))
|
|
542
|
+
.join("");
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Convert hex string to bytes.
|
|
547
|
+
*/
|
|
548
|
+
private hexToBytes(hex: string): Uint8Array {
|
|
549
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
550
|
+
for (let i = 0; i < hex.length; i += 2) {
|
|
551
|
+
bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16);
|
|
552
|
+
}
|
|
553
|
+
return bytes;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/**
|
|
557
|
+
* Simulate network delay.
|
|
558
|
+
*/
|
|
559
|
+
private async simulateNetworkDelay(baseMs: number): Promise<void> {
|
|
560
|
+
const jitter = Math.random() * baseMs * 0.2;
|
|
561
|
+
await this.delay(baseMs + jitter);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* Delay helper.
|
|
566
|
+
*/
|
|
567
|
+
private delay(ms: number): Promise<void> {
|
|
568
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
/**
|
|
572
|
+
* Debug logging helper.
|
|
573
|
+
*/
|
|
574
|
+
private debug(message: string): void {
|
|
575
|
+
if (this.options.debug) {
|
|
576
|
+
console.log(`[ProofServerClient] ${message}`);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
// =============================================================================
|
|
582
|
+
// FACTORY FUNCTION
|
|
583
|
+
// =============================================================================
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Create a new ProofServerClient instance.
|
|
587
|
+
*
|
|
588
|
+
* @param options - Configuration options
|
|
589
|
+
* @returns New ProofServerClient instance
|
|
590
|
+
*/
|
|
591
|
+
export function createProofServerClient(
|
|
592
|
+
options?: ProofServerClientOptions
|
|
593
|
+
): ProofServerClient {
|
|
594
|
+
return new ProofServerClient(options);
|
|
595
|
+
}
|