@izi-noir/sdk 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 (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +458 -0
  3. package/dist/IProvingSystem-D9TnEig0.d.ts +140 -0
  4. package/dist/IProvingSystem-TKNofoo8.d.cts +140 -0
  5. package/dist/index.cjs +2793 -0
  6. package/dist/index.cjs.map +1 -0
  7. package/dist/index.d.cts +1196 -0
  8. package/dist/index.d.ts +1196 -0
  9. package/dist/index.js +2730 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/providers/arkworks.cjs +824 -0
  12. package/dist/providers/arkworks.cjs.map +1 -0
  13. package/dist/providers/arkworks.d.cts +121 -0
  14. package/dist/providers/arkworks.d.ts +121 -0
  15. package/dist/providers/arkworks.js +791 -0
  16. package/dist/providers/arkworks.js.map +1 -0
  17. package/dist/providers/barretenberg.cjs +822 -0
  18. package/dist/providers/barretenberg.cjs.map +1 -0
  19. package/dist/providers/barretenberg.d.cts +18 -0
  20. package/dist/providers/barretenberg.d.ts +18 -0
  21. package/dist/providers/barretenberg.js +790 -0
  22. package/dist/providers/barretenberg.js.map +1 -0
  23. package/dist/providers/solana.cjs +262 -0
  24. package/dist/providers/solana.cjs.map +1 -0
  25. package/dist/providers/solana.d.cts +223 -0
  26. package/dist/providers/solana.d.ts +223 -0
  27. package/dist/providers/solana.js +222 -0
  28. package/dist/providers/solana.js.map +1 -0
  29. package/dist/providers/sunspot.cjs +475 -0
  30. package/dist/providers/sunspot.cjs.map +1 -0
  31. package/dist/providers/sunspot.d.cts +210 -0
  32. package/dist/providers/sunspot.d.ts +210 -0
  33. package/dist/providers/sunspot.js +443 -0
  34. package/dist/providers/sunspot.js.map +1 -0
  35. package/dist/types-CaaigonG.d.cts +93 -0
  36. package/dist/types-CaaigonG.d.ts +93 -0
  37. package/dist/wasm/nodejs/arkworks_groth16_wasm.js +448 -0
  38. package/dist/wasm/nodejs/arkworks_groth16_wasm_bg.wasm +0 -0
  39. package/dist/wasm/web/arkworks_groth16_wasm.js +536 -0
  40. package/dist/wasm/web/arkworks_groth16_wasm_bg.wasm +0 -0
  41. package/dist/wasmInit-KV6DTj4J.d.ts +282 -0
  42. package/dist/wasmInit-iEYiiB8M.d.cts +282 -0
  43. package/package.json +87 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,2793 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
11
+ var __export = (target, all) => {
12
+ for (var name in all)
13
+ __defProp(target, name, { get: all[name], enumerable: true });
14
+ };
15
+ var __copyProps = (to, from, except, desc) => {
16
+ if (from && typeof from === "object" || typeof from === "function") {
17
+ for (let key of __getOwnPropNames(from))
18
+ if (!__hasOwnProp.call(to, key) && key !== except)
19
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
20
+ }
21
+ return to;
22
+ };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
24
+ // If the importer is in node compatibility mode or this is not an ESM
25
+ // file that has been converted to a CommonJS file using a Babel-
26
+ // compatible transform (i.e. "__esModule" has not been set), then set
27
+ // "default" to the CommonJS "module.exports" for node compatibility.
28
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
29
+ mod
30
+ ));
31
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
+
33
+ // src/infra/provingSystems/Barretenberg.ts
34
+ var Barretenberg_exports = {};
35
+ __export(Barretenberg_exports, {
36
+ Barretenberg: () => Barretenberg
37
+ });
38
+ function stringToStream(content) {
39
+ return new ReadableStream({
40
+ start(controller) {
41
+ controller.enqueue(new TextEncoder().encode(content));
42
+ controller.close();
43
+ }
44
+ });
45
+ }
46
+ function isNodeJs2() {
47
+ return typeof globalThis.process !== "undefined" && globalThis.process.versions != null && globalThis.process.versions.node != null;
48
+ }
49
+ async function createTempDir() {
50
+ if (!isNodeJs2()) {
51
+ return { basePath: "/", cleanup: null };
52
+ }
53
+ const fs = await import("fs/promises");
54
+ const os = await import("os");
55
+ const path = await import("path");
56
+ const basePath = await fs.mkdtemp(path.join(os.tmpdir(), "noir-circuit-"));
57
+ const cleanup = async () => {
58
+ await fs.rm(basePath, { recursive: true, force: true });
59
+ };
60
+ return { basePath, cleanup };
61
+ }
62
+ var import_noir_wasm, import_noir_js, import_bb, Barretenberg;
63
+ var init_Barretenberg = __esm({
64
+ "src/infra/provingSystems/Barretenberg.ts"() {
65
+ "use strict";
66
+ import_noir_wasm = require("@noir-lang/noir_wasm");
67
+ import_noir_js = require("@noir-lang/noir_js");
68
+ import_bb = require("@aztec/bb.js");
69
+ Barretenberg = class {
70
+ async compile(noirCode) {
71
+ const { basePath, cleanup } = await createTempDir();
72
+ const fm = (0, import_noir_wasm.createFileManager)(basePath);
73
+ const nargoToml = `[package]
74
+ name = "circuit"
75
+ type = "bin"
76
+ authors = [""]
77
+
78
+ [dependencies]
79
+ `;
80
+ try {
81
+ if (isNodeJs2()) {
82
+ await fm.writeFile("./src/main.nr", stringToStream(noirCode));
83
+ await fm.writeFile("./Nargo.toml", stringToStream(nargoToml));
84
+ } else {
85
+ fm.writeFile("./src/main.nr", stringToStream(noirCode));
86
+ fm.writeFile("./Nargo.toml", stringToStream(nargoToml));
87
+ }
88
+ const result = await (0, import_noir_wasm.compile)(fm);
89
+ const compiled = result.program;
90
+ if (!compiled || !compiled.bytecode) {
91
+ throw new Error("Compilation failed: no bytecode generated");
92
+ }
93
+ return compiled;
94
+ } finally {
95
+ if (cleanup) {
96
+ await cleanup();
97
+ }
98
+ }
99
+ }
100
+ async generateProof(circuit, inputs) {
101
+ const noir = new import_noir_js.Noir(circuit);
102
+ const { witness } = await noir.execute(inputs);
103
+ const barretenberg = await import_bb.Barretenberg.new({ threads: 1 });
104
+ const backend = new import_bb.UltraHonkBackend(circuit.bytecode, barretenberg);
105
+ try {
106
+ const proofData = await backend.generateProof(witness);
107
+ return {
108
+ proof: proofData.proof,
109
+ publicInputs: proofData.publicInputs || []
110
+ };
111
+ } finally {
112
+ await barretenberg.destroy();
113
+ }
114
+ }
115
+ async verifyProof(circuit, proof, publicInputs) {
116
+ const barretenberg = await import_bb.Barretenberg.new({ threads: 1 });
117
+ const backend = new import_bb.UltraHonkBackend(circuit.bytecode, barretenberg);
118
+ try {
119
+ return await backend.verifyProof({ proof, publicInputs });
120
+ } finally {
121
+ await barretenberg.destroy();
122
+ }
123
+ }
124
+ };
125
+ }
126
+ });
127
+
128
+ // src/infra/provingSystems/ArkworksWasm.ts
129
+ var ArkworksWasm_exports = {};
130
+ __export(ArkworksWasm_exports, {
131
+ ArkworksWasm: () => ArkworksWasm,
132
+ isArkworksCircuit: () => isArkworksCircuit
133
+ });
134
+ function stringToStream2(content) {
135
+ return new ReadableStream({
136
+ start(controller) {
137
+ controller.enqueue(new TextEncoder().encode(content));
138
+ controller.close();
139
+ }
140
+ });
141
+ }
142
+ function isNodeJs3() {
143
+ return typeof globalThis.process !== "undefined" && globalThis.process.versions != null && globalThis.process.versions.node != null;
144
+ }
145
+ async function createTempDir2() {
146
+ if (!isNodeJs3()) {
147
+ return { basePath: "/", cleanup: null };
148
+ }
149
+ const fs = await import("fs/promises");
150
+ const os = await import("os");
151
+ const path = await import("path");
152
+ const basePath = await fs.mkdtemp(path.join(os.tmpdir(), "arkworks-circuit-"));
153
+ const cleanup = async () => {
154
+ await fs.rm(basePath, { recursive: true, force: true });
155
+ };
156
+ return { basePath, cleanup };
157
+ }
158
+ function isArkworksCircuit(circuit) {
159
+ return "__arkworks" in circuit && circuit.__arkworks === true;
160
+ }
161
+ async function initWasm() {
162
+ if (wasmModule) {
163
+ return wasmModule;
164
+ }
165
+ if (wasmInitPromise2) {
166
+ return wasmInitPromise2;
167
+ }
168
+ wasmInitPromise2 = (async () => {
169
+ try {
170
+ if (isNodeJs3()) {
171
+ const module2 = await import("../wasm/nodejs/arkworks_groth16_wasm.js");
172
+ wasmModule = module2;
173
+ } else {
174
+ const module2 = await import("../wasm/web/arkworks_groth16_wasm.js");
175
+ if (typeof module2.default === "function") {
176
+ await module2.default();
177
+ }
178
+ wasmModule = module2;
179
+ }
180
+ return wasmModule;
181
+ } catch (error) {
182
+ wasmInitPromise2 = null;
183
+ throw new Error(
184
+ `Failed to initialize arkworks-groth16-wasm: ${error instanceof Error ? error.message : String(error)}
185
+ Make sure the WASM module is built: cd packages/arkworks-groth16-wasm && npm run build`
186
+ );
187
+ }
188
+ })();
189
+ return wasmInitPromise2;
190
+ }
191
+ function base64ToUint8Array(b64) {
192
+ const binaryString = atob(b64);
193
+ const bytes = new Uint8Array(binaryString.length);
194
+ for (let i = 0; i < binaryString.length; i++) {
195
+ bytes[i] = binaryString.charCodeAt(i);
196
+ }
197
+ return bytes;
198
+ }
199
+ function uint8ArrayToBase64(bytes) {
200
+ let binary = "";
201
+ for (let i = 0; i < bytes.length; i++) {
202
+ binary += String.fromCharCode(bytes[i]);
203
+ }
204
+ return btoa(binary);
205
+ }
206
+ function publicInputsToGnarkBase64(publicInputs) {
207
+ const FIELD_SIZE2 = 32;
208
+ const bytes = new Uint8Array(publicInputs.length * FIELD_SIZE2);
209
+ for (let i = 0; i < publicInputs.length; i++) {
210
+ const input = publicInputs[i];
211
+ const hex = input.startsWith("0x") ? input.slice(2) : input;
212
+ const inputBytes = hexToBytes(hex.padStart(64, "0"));
213
+ bytes.set(inputBytes, i * FIELD_SIZE2);
214
+ }
215
+ return uint8ArrayToBase64(bytes);
216
+ }
217
+ function hexToBytes(hex) {
218
+ const bytes = new Uint8Array(hex.length / 2);
219
+ for (let i = 0; i < hex.length; i += 2) {
220
+ bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);
221
+ }
222
+ return bytes;
223
+ }
224
+ var import_noir_wasm2, import_noir_js2, wasmModule, wasmInitPromise2, ArkworksWasm;
225
+ var init_ArkworksWasm = __esm({
226
+ "src/infra/provingSystems/ArkworksWasm.ts"() {
227
+ "use strict";
228
+ import_noir_wasm2 = require("@noir-lang/noir_wasm");
229
+ import_noir_js2 = require("@noir-lang/noir_js");
230
+ wasmModule = null;
231
+ wasmInitPromise2 = null;
232
+ ArkworksWasm = class {
233
+ config;
234
+ constructor(config = {}) {
235
+ this.config = {
236
+ keepArtifacts: false,
237
+ cacheKeys: true,
238
+ ...config
239
+ };
240
+ }
241
+ /**
242
+ * Compile Noir code to a circuit with ACIR for Groth16 proving
243
+ */
244
+ async compile(noirCode) {
245
+ const wasm = await initWasm();
246
+ const { basePath, cleanup } = await createTempDir2();
247
+ const fm = (0, import_noir_wasm2.createFileManager)(basePath);
248
+ const nargoToml = `[package]
249
+ name = "circuit"
250
+ type = "bin"
251
+ authors = [""]
252
+
253
+ [dependencies]
254
+ `;
255
+ try {
256
+ if (isNodeJs3()) {
257
+ await fm.writeFile("./src/main.nr", stringToStream2(noirCode));
258
+ await fm.writeFile("./Nargo.toml", stringToStream2(nargoToml));
259
+ } else {
260
+ fm.writeFile("./src/main.nr", stringToStream2(noirCode));
261
+ fm.writeFile("./Nargo.toml", stringToStream2(nargoToml));
262
+ }
263
+ const result = await (0, import_noir_wasm2.compile)(fm);
264
+ const compiled = result.program;
265
+ if (!compiled || !compiled.bytecode) {
266
+ throw new Error("Compilation failed: no bytecode generated");
267
+ }
268
+ const acirJson = JSON.stringify({
269
+ functions: [
270
+ {
271
+ current_witness_index: compiled.abi.parameters.length + 1,
272
+ opcodes: [],
273
+ // Will be extracted from bytecode during prove
274
+ private_parameters: compiled.abi.parameters.filter((p) => p.visibility === "private").map((_, i) => i + 1),
275
+ public_parameters: {
276
+ witnesses: compiled.abi.parameters.filter((p) => p.visibility === "public").map((_, i) => i + 1)
277
+ },
278
+ return_values: { witnesses: [] }
279
+ }
280
+ ]
281
+ });
282
+ let provingKey;
283
+ let verifyingKey;
284
+ let verifyingKeyGnark;
285
+ if (this.config.cacheKeys) {
286
+ try {
287
+ const setupResult = wasm.setup(acirJson);
288
+ provingKey = setupResult.proving_key;
289
+ verifyingKey = setupResult.verifying_key;
290
+ verifyingKeyGnark = setupResult.verifying_key_gnark;
291
+ } catch (error) {
292
+ console.warn("Deferred setup: will run during proof generation");
293
+ }
294
+ }
295
+ const arkworksCircuit = {
296
+ ...compiled,
297
+ __arkworks: true,
298
+ acirJson,
299
+ provingKey,
300
+ verifyingKey,
301
+ verifyingKeyGnark
302
+ };
303
+ return arkworksCircuit;
304
+ } finally {
305
+ if (cleanup) {
306
+ await cleanup();
307
+ }
308
+ }
309
+ }
310
+ /**
311
+ * Generate a Groth16 proof
312
+ */
313
+ async generateProof(circuit, inputs) {
314
+ const wasm = await initWasm();
315
+ if (!isArkworksCircuit(circuit)) {
316
+ throw new Error(
317
+ "ArkworksWasm.generateProof requires an ArkworksCompiledCircuit. Use ArkworksWasm.compile() first."
318
+ );
319
+ }
320
+ const noir = new import_noir_js2.Noir(circuit);
321
+ const { witness } = await noir.execute(inputs);
322
+ const witnessMap = {};
323
+ for (const [index, value] of witness.entries()) {
324
+ witnessMap[index.toString()] = String(value);
325
+ }
326
+ const witnessJson = JSON.stringify(witnessMap);
327
+ let provingKey = circuit.provingKey;
328
+ if (!provingKey) {
329
+ const setupResult = wasm.setup(circuit.acirJson);
330
+ provingKey = setupResult.proving_key;
331
+ circuit.provingKey = provingKey;
332
+ circuit.verifyingKey = setupResult.verifying_key;
333
+ circuit.verifyingKeyGnark = setupResult.verifying_key_gnark;
334
+ }
335
+ const proofResult = wasm.prove(provingKey, circuit.acirJson, witnessJson);
336
+ const proofBytes = base64ToUint8Array(proofResult.proof_gnark);
337
+ return {
338
+ proof: proofBytes,
339
+ publicInputs: proofResult.public_inputs
340
+ };
341
+ }
342
+ /**
343
+ * Verify a Groth16 proof
344
+ */
345
+ async verifyProof(circuit, proof, publicInputs) {
346
+ const wasm = await initWasm();
347
+ if (!isArkworksCircuit(circuit)) {
348
+ throw new Error(
349
+ "ArkworksWasm.verifyProof requires an ArkworksCompiledCircuit. Use ArkworksWasm.compile() first."
350
+ );
351
+ }
352
+ let verifyingKeyGnark = circuit.verifyingKeyGnark;
353
+ if (!verifyingKeyGnark) {
354
+ const setupResult = wasm.setup(circuit.acirJson);
355
+ circuit.provingKey = setupResult.proving_key;
356
+ circuit.verifyingKey = setupResult.verifying_key;
357
+ verifyingKeyGnark = setupResult.verifying_key_gnark;
358
+ circuit.verifyingKeyGnark = verifyingKeyGnark;
359
+ }
360
+ const proofB64 = uint8ArrayToBase64(proof);
361
+ const publicInputsGnarkB64 = publicInputsToGnarkBase64(publicInputs);
362
+ return wasm.verify_gnark(
363
+ verifyingKeyGnark,
364
+ proofB64,
365
+ publicInputsGnarkB64,
366
+ publicInputs.length
367
+ );
368
+ }
369
+ /**
370
+ * Get the verifying key in gnark format for on-chain deployment
371
+ */
372
+ async getVerifyingKeyGnark(circuit) {
373
+ const wasm = await initWasm();
374
+ if (!isArkworksCircuit(circuit)) {
375
+ throw new Error("getVerifyingKeyGnark requires an ArkworksCompiledCircuit");
376
+ }
377
+ if (!circuit.verifyingKeyGnark) {
378
+ const setupResult = wasm.setup(circuit.acirJson);
379
+ circuit.provingKey = setupResult.proving_key;
380
+ circuit.verifyingKey = setupResult.verifying_key;
381
+ circuit.verifyingKeyGnark = setupResult.verifying_key_gnark;
382
+ }
383
+ return base64ToUint8Array(circuit.verifyingKeyGnark);
384
+ }
385
+ };
386
+ }
387
+ });
388
+
389
+ // src/infra/chainFormatters/SolanaFormatter.ts
390
+ var SolanaFormatter_exports = {};
391
+ __export(SolanaFormatter_exports, {
392
+ SolanaFormatter: () => SolanaFormatter
393
+ });
394
+ var G1_SIZE, G2_SIZE, SolanaFormatter;
395
+ var init_SolanaFormatter = __esm({
396
+ "src/infra/chainFormatters/SolanaFormatter.ts"() {
397
+ "use strict";
398
+ G1_SIZE = 64;
399
+ G2_SIZE = 128;
400
+ SolanaFormatter = class {
401
+ constructor(arkworksProvider) {
402
+ this.arkworksProvider = arkworksProvider;
403
+ }
404
+ chainId = "solana";
405
+ /**
406
+ * Format a generic proof for Solana on-chain verification.
407
+ *
408
+ * @param proofData - Generic proof data from Arkworks
409
+ * @param circuit - The compiled circuit (must be Arkworks circuit)
410
+ * @param metadata - Circuit metadata with public input count
411
+ * @returns SolanaProofData ready for on-chain verification
412
+ */
413
+ async formatProof(proofData, circuit, metadata) {
414
+ const vkBytes = await this.arkworksProvider.getVerifyingKeyGnark(circuit);
415
+ const vkBase64 = this.uint8ArrayToBase64(vkBytes);
416
+ const nrPublicInputs = metadata.numPublicInputs;
417
+ const publicInputsBytes = proofData.publicInputs.map((input) => {
418
+ const hex = input.startsWith("0x") ? input.slice(2) : input;
419
+ return this.hexToBytes(hex.padStart(64, "0"));
420
+ });
421
+ const { accountSize, estimatedRent } = this.getChainMetadata(nrPublicInputs);
422
+ return {
423
+ verifyingKey: {
424
+ base64: vkBase64,
425
+ bytes: vkBytes,
426
+ nrPublicInputs
427
+ },
428
+ proof: {
429
+ base64: this.uint8ArrayToBase64(proofData.proof),
430
+ bytes: proofData.proof
431
+ },
432
+ publicInputs: {
433
+ hex: proofData.publicInputs,
434
+ bytes: publicInputsBytes
435
+ },
436
+ accountSize,
437
+ estimatedRent
438
+ };
439
+ }
440
+ /**
441
+ * Get Solana-specific metadata for a circuit.
442
+ *
443
+ * @param publicInputCount - Number of public inputs in the circuit
444
+ * @returns Solana metadata with account size and rent estimates
445
+ */
446
+ getChainMetadata(publicInputCount) {
447
+ const accountSize = this.calculateVkAccountSize(publicInputCount);
448
+ const estimatedRent = this.calculateVkAccountRent(publicInputCount);
449
+ return {
450
+ chainId: "solana",
451
+ accountSize,
452
+ estimatedRent
453
+ };
454
+ }
455
+ /**
456
+ * Calculate the size of a VK account for a given number of public inputs.
457
+ * Matches the Rust `vk_account_size` function in the Solana program.
458
+ */
459
+ calculateVkAccountSize(nrPublicInputs) {
460
+ const fixedSize = 8 + 32 + 1 + G1_SIZE + G2_SIZE * 3 + 4;
461
+ return fixedSize + (nrPublicInputs + 1) * G1_SIZE;
462
+ }
463
+ /**
464
+ * Calculate the minimum rent for a VK account.
465
+ */
466
+ calculateVkAccountRent(nrPublicInputs, rentExemptionPerByte = 6960) {
467
+ const size = this.calculateVkAccountSize(nrPublicInputs);
468
+ return size * rentExemptionPerByte;
469
+ }
470
+ /**
471
+ * Convert Uint8Array to base64 string.
472
+ */
473
+ uint8ArrayToBase64(bytes) {
474
+ if (typeof btoa === "function") {
475
+ let binary = "";
476
+ for (let i = 0; i < bytes.length; i++) {
477
+ binary += String.fromCharCode(bytes[i]);
478
+ }
479
+ return btoa(binary);
480
+ }
481
+ return Buffer.from(bytes).toString("base64");
482
+ }
483
+ /**
484
+ * Convert hex string to Uint8Array.
485
+ */
486
+ hexToBytes(hex) {
487
+ const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
488
+ const bytes = new Uint8Array(cleanHex.length / 2);
489
+ for (let i = 0; i < bytes.length; i++) {
490
+ bytes[i] = parseInt(cleanHex.substring(i * 2, i * 2 + 2), 16);
491
+ }
492
+ return bytes;
493
+ }
494
+ };
495
+ }
496
+ });
497
+
498
+ // src/index.ts
499
+ var index_exports = {};
500
+ __export(index_exports, {
501
+ AcornParser: () => AcornParser,
502
+ ArkworksWasm: () => ArkworksWasm,
503
+ Barretenberg: () => Barretenberg,
504
+ Chain: () => Chain,
505
+ CircuitRegistry: () => CircuitRegistry,
506
+ CreateProofUseCase: () => CreateProofUseCase,
507
+ IZI_NOIR_PROGRAM_ID: () => IZI_NOIR_PROGRAM_ID,
508
+ IziNoir: () => IziNoir,
509
+ NETWORK_ENDPOINTS: () => NETWORK_ENDPOINTS,
510
+ OffchainVerifier: () => OffchainVerifier,
511
+ Provider: () => Provider,
512
+ SolanaFormatter: () => SolanaFormatter,
513
+ SolanaTransactionBuilder: () => SolanaTransactionBuilder,
514
+ VkDeploymentManager: () => VkDeploymentManager,
515
+ batchVerify: () => batchVerify,
516
+ buildInitVkFromBytesData: () => buildInitVkFromBytesData,
517
+ buildVerifyProofData: () => buildVerifyProofData,
518
+ calculateVkAccountRent: () => calculateVkAccountRent,
519
+ calculateVkAccountSize: () => calculateVkAccountSize,
520
+ createArkworksWasmContainer: () => createArkworksWasmContainer,
521
+ createDefaultContainer: () => createDefaultContainer,
522
+ createNodeVkDeploymentManager: () => createNodeVkDeploymentManager,
523
+ createVerificationEndpoint: () => createVerificationEndpoint,
524
+ createVerifierMiddleware: () => createVerifierMiddleware,
525
+ defineCircuit: () => defineCircuit,
526
+ generateNoir: () => generateNoir,
527
+ getGlobalRegistry: () => getGlobalRegistry,
528
+ initNoirWasm: () => initNoirWasm,
529
+ isArkworksCircuit: () => isArkworksCircuit,
530
+ isWasmInitialized: () => isWasmInitialized,
531
+ markWasmInitialized: () => markWasmInitialized,
532
+ parseProof: () => parseProof,
533
+ parsePublicInputs: () => parsePublicInputs,
534
+ parseVerifyingKey: () => parseVerifyingKey
535
+ });
536
+ module.exports = __toCommonJS(index_exports);
537
+
538
+ // src/domain/types/chain.ts
539
+ var Chain = /* @__PURE__ */ ((Chain2) => {
540
+ Chain2["Solana"] = "solana";
541
+ Chain2["Ethereum"] = "ethereum";
542
+ return Chain2;
543
+ })(Chain || {});
544
+
545
+ // src/domain/types/provider.ts
546
+ var Provider = /* @__PURE__ */ ((Provider2) => {
547
+ Provider2["Barretenberg"] = "barretenberg";
548
+ Provider2["Arkworks"] = "arkworks";
549
+ Provider2["Sunspot"] = "sunspot";
550
+ return Provider2;
551
+ })(Provider || {});
552
+
553
+ // src/infra/wasm/wasmInit.ts
554
+ var wasmInitPromise = null;
555
+ var wasmInitialized = false;
556
+ function isNodeJs() {
557
+ return typeof globalThis.process !== "undefined" && globalThis.process.versions != null && globalThis.process.versions.node != null;
558
+ }
559
+ async function initNoirWasm() {
560
+ if (wasmInitialized) return;
561
+ if (!wasmInitPromise) {
562
+ wasmInitPromise = initWasmInternal();
563
+ }
564
+ await wasmInitPromise;
565
+ wasmInitialized = true;
566
+ }
567
+ async function initWasmInternal() {
568
+ if (isNodeJs()) {
569
+ await import("@noir-lang/acvm_js/nodejs/acvm_js.js");
570
+ await import("@noir-lang/noirc_abi/nodejs/noirc_abi_wasm.js");
571
+ } else {
572
+ const [{ default: initACVM }, { default: initNoirC }] = await Promise.all([
573
+ import("@noir-lang/acvm_js"),
574
+ import("@noir-lang/noirc_abi")
575
+ ]);
576
+ await Promise.all([initACVM(), initNoirC()]);
577
+ }
578
+ }
579
+ function isWasmInitialized() {
580
+ return wasmInitialized;
581
+ }
582
+ function markWasmInitialized() {
583
+ wasmInitialized = true;
584
+ }
585
+
586
+ // src/IziNoir.ts
587
+ var IziNoir = class _IziNoir {
588
+ provingSystem;
589
+ compiledCircuit = null;
590
+ chainFormatters = /* @__PURE__ */ new Map();
591
+ chain;
592
+ _verifyingKey;
593
+ _lastProof;
594
+ constructor(provingSystem, chain) {
595
+ this.provingSystem = provingSystem;
596
+ this.chain = chain;
597
+ }
598
+ /**
599
+ * Get the verifying key from the last proof generation.
600
+ * Only available after calling prove() with a chain configured.
601
+ */
602
+ get vk() {
603
+ return this._verifyingKey;
604
+ }
605
+ /**
606
+ * Get the configured chain, if any.
607
+ */
608
+ get targetChain() {
609
+ return this.chain;
610
+ }
611
+ /**
612
+ * Check if operating in offchain mode (no chain configured).
613
+ */
614
+ get isOffchain() {
615
+ return this.chain === void 0;
616
+ }
617
+ /**
618
+ * Register a chain formatter for chain-specific proof formatting.
619
+ *
620
+ * @param formatter - The chain formatter to register
621
+ */
622
+ registerChainFormatter(formatter) {
623
+ this.chainFormatters.set(formatter.chainId, formatter);
624
+ }
625
+ /**
626
+ * Get a registered chain formatter.
627
+ *
628
+ * @param chainId - The chain ID to get the formatter for
629
+ * @returns The formatter or undefined if not registered
630
+ */
631
+ getChainFormatter(chainId) {
632
+ return this.chainFormatters.get(chainId);
633
+ }
634
+ /**
635
+ * Initialize IziNoir with the specified provider and optional chain.
636
+ *
637
+ * @param config - Configuration specifying the provider, chain, and optional circuit paths
638
+ * @returns Initialized IziNoir instance
639
+ *
640
+ * @example
641
+ * ```typescript
642
+ * // On-chain mode (Solana)
643
+ * const izi = await IziNoir.init({
644
+ * provider: Provider.Arkworks,
645
+ * chain: Chain.Solana
646
+ * });
647
+ *
648
+ * // Offchain mode (no chain formatting)
649
+ * const iziOffchain = await IziNoir.init({
650
+ * provider: Provider.Arkworks
651
+ * });
652
+ *
653
+ * // Barretenberg (browser-compatible, ~16KB proofs, offchain only)
654
+ * const bb = await IziNoir.init({ provider: Provider.Barretenberg });
655
+ * ```
656
+ */
657
+ static async init(config) {
658
+ await initNoirWasm();
659
+ let provingSystem;
660
+ switch (config.provider) {
661
+ case "barretenberg" /* Barretenberg */: {
662
+ if (config.chain) {
663
+ throw new Error(
664
+ "Barretenberg provider does not support chain formatting. Use Provider.Arkworks for on-chain proofs."
665
+ );
666
+ }
667
+ const { Barretenberg: Barretenberg2 } = await Promise.resolve().then(() => (init_Barretenberg(), Barretenberg_exports));
668
+ provingSystem = new Barretenberg2();
669
+ return new _IziNoir(provingSystem);
670
+ }
671
+ case "arkworks" /* Arkworks */: {
672
+ const { ArkworksWasm: ArkworksWasm2 } = await Promise.resolve().then(() => (init_ArkworksWasm(), ArkworksWasm_exports));
673
+ const arkworksInstance = new ArkworksWasm2();
674
+ provingSystem = arkworksInstance;
675
+ const instance = new _IziNoir(provingSystem, config.chain);
676
+ if (config.chain === "solana" /* Solana */ || !config.chain) {
677
+ const { SolanaFormatter: SolanaFormatter2 } = await Promise.resolve().then(() => (init_SolanaFormatter(), SolanaFormatter_exports));
678
+ instance.registerChainFormatter(new SolanaFormatter2(arkworksInstance));
679
+ }
680
+ return instance;
681
+ }
682
+ case "sunspot" /* Sunspot */: {
683
+ throw new Error(
684
+ 'Sunspot is not available in the main entry point. Import from "@izi-noir/sdk/sunspot" for Sunspot support.'
685
+ );
686
+ }
687
+ default:
688
+ throw new Error(`Unknown provider: ${config.provider}`);
689
+ }
690
+ }
691
+ /**
692
+ * Get the underlying proving system instance.
693
+ * Useful for advanced use cases.
694
+ */
695
+ getProvingSystem() {
696
+ return this.provingSystem;
697
+ }
698
+ /**
699
+ * Get the currently compiled circuit, if any.
700
+ */
701
+ getCompiledCircuit() {
702
+ return this.compiledCircuit;
703
+ }
704
+ /**
705
+ * Compile Noir code into a circuit.
706
+ *
707
+ * @param noirCode - The Noir source code to compile
708
+ * @returns The compiled circuit
709
+ */
710
+ async compile(noirCode) {
711
+ this.compiledCircuit = await this.provingSystem.compile(noirCode);
712
+ return this.compiledCircuit;
713
+ }
714
+ /**
715
+ * Generate a proof for the given inputs.
716
+ *
717
+ * If a chain is configured, returns chain-formatted proof data and stores
718
+ * the verifying key in `this.vk`. Otherwise, returns raw proof data.
719
+ *
720
+ * @param inputs - The inputs (both public and private) for the circuit
721
+ * @param circuit - Optional circuit to use (defaults to last compiled circuit)
722
+ * @returns The proof data - type depends on configured chain
723
+ * @throws Error if no circuit is available
724
+ *
725
+ * @example
726
+ * ```typescript
727
+ * // With chain configured - returns SolanaProofData
728
+ * const izi = await IziNoir.init({ provider: Provider.Arkworks, chain: Chain.Solana });
729
+ * await izi.compile(noirCode);
730
+ * const proof = await izi.prove({ expected: '100', secret: '10' });
731
+ * // proof is SolanaProofData, izi.vk is available
732
+ *
733
+ * // Offchain mode - returns ProofData
734
+ * const iziOffchain = await IziNoir.init({ provider: Provider.Arkworks });
735
+ * await iziOffchain.compile(noirCode);
736
+ * const rawProof = await iziOffchain.prove({ expected: '100', secret: '10' });
737
+ * // rawProof is ProofData, iziOffchain.vk is undefined
738
+ * ```
739
+ */
740
+ async prove(inputs, circuit) {
741
+ const circuitToUse = circuit || this.compiledCircuit;
742
+ if (!circuitToUse) {
743
+ throw new Error("No circuit available. Call compile() first or provide a circuit.");
744
+ }
745
+ const rawProof = await this.provingSystem.generateProof(circuitToUse, inputs);
746
+ if (!this.chain) {
747
+ this._lastProof = rawProof;
748
+ return rawProof;
749
+ }
750
+ const formatter = this.chainFormatters.get(this.chain);
751
+ if (!formatter) {
752
+ throw new Error(
753
+ `No formatter registered for chain: ${this.chain}. This is an internal error - please report it.`
754
+ );
755
+ }
756
+ const metadata = {
757
+ numPublicInputs: rawProof.publicInputs.length
758
+ };
759
+ const formattedProof = await formatter.formatProof(rawProof, circuitToUse, metadata);
760
+ const chainProof = formattedProof;
761
+ this._verifyingKey = chainProof.verifyingKey;
762
+ this._lastProof = chainProof;
763
+ return chainProof;
764
+ }
765
+ /**
766
+ * Verify a proof.
767
+ * Available in both on-chain and offchain modes.
768
+ *
769
+ * @param proof - The proof bytes to verify
770
+ * @param publicInputs - The public inputs that were used
771
+ * @param circuit - Optional circuit to use (defaults to last compiled circuit)
772
+ * @returns true if the proof is valid, false otherwise
773
+ * @throws Error if no circuit is available
774
+ */
775
+ async verify(proof, publicInputs, circuit) {
776
+ const circuitToUse = circuit || this.compiledCircuit;
777
+ if (!circuitToUse) {
778
+ throw new Error("No circuit available. Call compile() first or provide a circuit.");
779
+ }
780
+ return this.provingSystem.verifyProof(circuitToUse, proof, publicInputs);
781
+ }
782
+ /**
783
+ * Convenience method: compile, prove, and verify in one call.
784
+ *
785
+ * @param noirCode - The Noir source code to compile
786
+ * @param inputs - The inputs (both public and private) for the circuit
787
+ * @returns Object containing proof data and verification result
788
+ *
789
+ * @example
790
+ * ```typescript
791
+ * const { proof, verified } = await izi.createProof(noirCode, {
792
+ * x: '100',
793
+ * y: '10',
794
+ * });
795
+ * console.log(`Verified: ${verified}`);
796
+ * ```
797
+ */
798
+ async createProof(noirCode, inputs) {
799
+ const circuit = await this.compile(noirCode);
800
+ const proof = await this.prove(inputs, circuit);
801
+ const proofBytes = "proof" in proof && proof.proof instanceof Uint8Array ? proof.proof : proof.proof.bytes;
802
+ const pubInputs = Array.isArray(proof.publicInputs) ? proof.publicInputs : proof.publicInputs.hex;
803
+ const verified = await this.verify(proofBytes, pubInputs, circuit);
804
+ return { proof, verified };
805
+ }
806
+ /**
807
+ * Get deployment data for the verifying key.
808
+ * Returns the data needed to deploy to the configured blockchain.
809
+ * Use with SolanaTransactionBuilder to build and send the transaction.
810
+ *
811
+ * @param options - Optional configuration
812
+ * @returns Deployment data that can be used with SolanaTransactionBuilder
813
+ * @throws Error if no chain is configured (offchain mode)
814
+ * @throws Error if prove() hasn't been called yet
815
+ *
816
+ * @example
817
+ * ```typescript
818
+ * const izi = await IziNoir.init({ provider: Provider.Arkworks, chain: Chain.Solana });
819
+ * await izi.compile(noirCode);
820
+ * await izi.prove(inputs);
821
+ *
822
+ * // Get deployment data
823
+ * const deployData = izi.getDeployData();
824
+ *
825
+ * // Use with SolanaTransactionBuilder in your frontend
826
+ * const builder = new SolanaTransactionBuilder({ programId: deployData.programId });
827
+ * const { initVk, rentLamports, accountSize } = builder.buildInitAndVerifyInstructions(
828
+ * deployData.proofData,
829
+ * vkAccountPubkey,
830
+ * authority,
831
+ * payer
832
+ * );
833
+ * ```
834
+ */
835
+ getDeployData(options) {
836
+ if (!this.chain) {
837
+ throw new Error("Cannot deploy in offchain mode. Initialize with a chain parameter.");
838
+ }
839
+ if (!this._verifyingKey || !this._lastProof) {
840
+ throw new Error("Must call prove() before getDeployData().");
841
+ }
842
+ if (this.chain !== "solana" /* Solana */) {
843
+ throw new Error(`Deployment for ${this.chain} is not yet supported.`);
844
+ }
845
+ return {
846
+ proofData: this._lastProof,
847
+ programId: options?.programId ?? "EYhRED7EuMyyVjx57aDXUD9h6ArnEKng64qtz8999KrS",
848
+ computeUnits: options?.computeUnits ?? 4e5
849
+ };
850
+ }
851
+ };
852
+
853
+ // src/index.ts
854
+ init_SolanaFormatter();
855
+ init_Barretenberg();
856
+ init_ArkworksWasm();
857
+
858
+ // src/infra/parser/AcornParser.ts
859
+ var acorn = __toESM(require("acorn"), 1);
860
+ var walk = __toESM(require("acorn-walk"), 1);
861
+
862
+ // src/infra/parser/operatorMaps.ts
863
+ var BINARY_OPERATOR_MAP = {
864
+ // Equality
865
+ "==": "==",
866
+ "===": "==",
867
+ "!=": "!=",
868
+ "!==": "!=",
869
+ // Arithmetic
870
+ "+": "+",
871
+ "-": "-",
872
+ "*": "*",
873
+ "/": "/",
874
+ "%": "%",
875
+ // Comparison
876
+ "<": "<",
877
+ ">": ">",
878
+ "<=": "<=",
879
+ ">=": ">=",
880
+ // Logical (JS && and || map to Noir & and |)
881
+ "&&": "&",
882
+ "||": "|"
883
+ };
884
+ var UNARY_OPERATOR_MAP = {
885
+ "!": "!",
886
+ "-": "-"
887
+ };
888
+
889
+ // src/infra/parser/utils.ts
890
+ var MUT_PREFIX = "mut_";
891
+ function stripMutPrefix(name) {
892
+ return name.startsWith(MUT_PREFIX) ? name.slice(MUT_PREFIX.length) : name;
893
+ }
894
+ function isMutable(name) {
895
+ return name.startsWith(MUT_PREFIX);
896
+ }
897
+
898
+ // src/infra/parser/ExpressionParser.ts
899
+ var ExpressionParser = class {
900
+ /**
901
+ * Parses an AST node into a circuit expression.
902
+ * @returns The parsed expression, or null if the node type is not recognized.
903
+ */
904
+ parse(node) {
905
+ switch (node.type) {
906
+ case "Identifier":
907
+ return this.parseIdentifier(node);
908
+ case "Literal":
909
+ return this.parseLiteral(node);
910
+ case "BinaryExpression":
911
+ case "LogicalExpression":
912
+ return this.parseBinaryExpression(node);
913
+ case "MemberExpression":
914
+ return this.parseMemberExpression(node);
915
+ case "ArrayExpression":
916
+ return this.parseArrayExpression(node);
917
+ case "CallExpression":
918
+ return this.parseCallExpression(node);
919
+ case "UnaryExpression":
920
+ return this.parseUnaryExpression(node);
921
+ case "ConditionalExpression":
922
+ return this.parseConditionalExpression(node);
923
+ default:
924
+ return null;
925
+ }
926
+ }
927
+ parseIdentifier(node) {
928
+ const name = node.name;
929
+ return { kind: "identifier", name: stripMutPrefix(name) };
930
+ }
931
+ parseLiteral(node) {
932
+ return { kind: "literal", value: node.value };
933
+ }
934
+ parseBinaryExpression(node) {
935
+ const operator = BINARY_OPERATOR_MAP[node.operator];
936
+ if (!operator) {
937
+ throw new Error(`Unsupported operator: ${node.operator}`);
938
+ }
939
+ const left = this.parse(node.left);
940
+ const right = this.parse(node.right);
941
+ if (!left || !right) {
942
+ throw new Error("Could not parse binary expression operands");
943
+ }
944
+ return { kind: "binary", left, operator, right };
945
+ }
946
+ parseMemberExpression(node) {
947
+ const obj = node.object;
948
+ const prop = node.property;
949
+ if (node.computed) {
950
+ const object = this.parse(obj);
951
+ const index = this.parse(prop);
952
+ if (!object || !index) {
953
+ throw new Error("Could not parse member expression");
954
+ }
955
+ return {
956
+ kind: "member",
957
+ object,
958
+ index
959
+ };
960
+ }
961
+ if (prop.type === "Identifier" && prop.name === "length") {
962
+ const object = this.parse(obj);
963
+ if (!object) {
964
+ throw new Error("Could not parse object for .length");
965
+ }
966
+ return {
967
+ kind: "call",
968
+ callee: object,
969
+ method: "len",
970
+ args: []
971
+ };
972
+ }
973
+ return null;
974
+ }
975
+ parseArrayExpression(node) {
976
+ const elements = [];
977
+ for (const elem of node.elements) {
978
+ if (elem) {
979
+ const parsed = this.parse(elem);
980
+ if (parsed) {
981
+ elements.push(parsed);
982
+ }
983
+ }
984
+ }
985
+ return {
986
+ kind: "array_literal",
987
+ elements
988
+ };
989
+ }
990
+ parseCallExpression(node) {
991
+ const callee = node.callee;
992
+ const args = [];
993
+ for (const arg of node.arguments) {
994
+ const parsed = this.parse(arg);
995
+ if (parsed) {
996
+ args.push(parsed);
997
+ }
998
+ }
999
+ if (callee.type === "MemberExpression" && !callee.computed) {
1000
+ const obj = this.parse(callee.object);
1001
+ const method = callee.property.name;
1002
+ if (obj) {
1003
+ return {
1004
+ kind: "call",
1005
+ callee: obj,
1006
+ method,
1007
+ args
1008
+ };
1009
+ }
1010
+ }
1011
+ const calleeExpr = this.parse(callee);
1012
+ if (calleeExpr) {
1013
+ return {
1014
+ kind: "call",
1015
+ callee: calleeExpr,
1016
+ args
1017
+ };
1018
+ }
1019
+ return null;
1020
+ }
1021
+ parseUnaryExpression(node) {
1022
+ const unaryOp = UNARY_OPERATOR_MAP[node.operator];
1023
+ if (!unaryOp) {
1024
+ throw new Error(`Unsupported unary operator: ${node.operator}`);
1025
+ }
1026
+ if (node.operator === "-" && node.argument.type === "Literal") {
1027
+ const val = node.argument.value;
1028
+ if (typeof val === "number" || typeof val === "bigint") {
1029
+ return { kind: "literal", value: -val };
1030
+ }
1031
+ }
1032
+ const operand = this.parse(node.argument);
1033
+ if (!operand) {
1034
+ throw new Error("Could not parse unary expression operand");
1035
+ }
1036
+ return { kind: "unary", operator: unaryOp, operand };
1037
+ }
1038
+ parseConditionalExpression(node) {
1039
+ const condition = this.parse(node.test);
1040
+ const consequent = this.parse(node.consequent);
1041
+ const alternate = this.parse(node.alternate);
1042
+ if (!condition || !consequent || !alternate) {
1043
+ throw new Error("Could not parse ternary expression");
1044
+ }
1045
+ return {
1046
+ kind: "if_expr",
1047
+ condition,
1048
+ consequent,
1049
+ alternate
1050
+ };
1051
+ }
1052
+ };
1053
+
1054
+ // src/infra/parser/StatementParser.ts
1055
+ var StatementParser = class {
1056
+ constructor(exprParser, forLoopParser) {
1057
+ this.exprParser = exprParser;
1058
+ this.forLoopParser = forLoopParser;
1059
+ }
1060
+ /**
1061
+ * Parses a statement AST node.
1062
+ * @returns The parsed statement, or null if the node type is not recognized.
1063
+ */
1064
+ parse(node) {
1065
+ switch (node.type) {
1066
+ case "VariableDeclaration":
1067
+ return this.parseVariableDeclaration(node);
1068
+ case "ExpressionStatement":
1069
+ return this.parseExpressionStatement(node);
1070
+ case "IfStatement":
1071
+ return this.parseIfStatement(node);
1072
+ case "ForStatement":
1073
+ return this.forLoopParser.parse(node, (n) => this.parseBlock(n));
1074
+ default:
1075
+ return null;
1076
+ }
1077
+ }
1078
+ /**
1079
+ * Parses a block or single statement into an array of statements.
1080
+ */
1081
+ parseBlock(node) {
1082
+ if (node.type === "BlockStatement") {
1083
+ const statements = [];
1084
+ for (const stmt of node.body) {
1085
+ const parsed = this.parse(stmt);
1086
+ if (parsed) {
1087
+ statements.push(parsed);
1088
+ }
1089
+ }
1090
+ return statements;
1091
+ } else {
1092
+ const parsed = this.parse(node);
1093
+ return parsed ? [parsed] : [];
1094
+ }
1095
+ }
1096
+ /**
1097
+ * Parses variable declarations: let x = 5; const y = 10;
1098
+ * Uses mut_ prefix convention for mutable variables.
1099
+ */
1100
+ parseVariableDeclaration(node) {
1101
+ const declaration = node.declarations[0];
1102
+ if (!declaration || declaration.type !== "VariableDeclarator") {
1103
+ throw new Error("Invalid variable declaration");
1104
+ }
1105
+ const id = declaration.id;
1106
+ if (id.type !== "Identifier") {
1107
+ throw new Error("Variable declaration must have a simple identifier");
1108
+ }
1109
+ const init = declaration.init;
1110
+ if (!init) {
1111
+ throw new Error("Variable declaration must have an initializer");
1112
+ }
1113
+ const initializer = this.exprParser.parse(init);
1114
+ if (!initializer) {
1115
+ throw new Error("Could not parse variable initializer");
1116
+ }
1117
+ const name = id.name;
1118
+ return {
1119
+ kind: "variable_declaration",
1120
+ name: stripMutPrefix(name),
1121
+ mutable: isMutable(name),
1122
+ initializer
1123
+ };
1124
+ }
1125
+ /**
1126
+ * Parses expression statements: assert(), assignments.
1127
+ */
1128
+ parseExpressionStatement(node) {
1129
+ const expr = node.expression;
1130
+ if (expr.type === "CallExpression") {
1131
+ const callee = expr.callee;
1132
+ if (callee.type === "Identifier" && callee.name === "assert") {
1133
+ return this.parseAssertCall(expr);
1134
+ }
1135
+ }
1136
+ if (expr.type === "AssignmentExpression") {
1137
+ return this.parseAssignment(expr);
1138
+ }
1139
+ return null;
1140
+ }
1141
+ /**
1142
+ * Parses assert() function calls.
1143
+ */
1144
+ parseAssertCall(expr) {
1145
+ const args = expr.arguments;
1146
+ if (args.length === 0) {
1147
+ throw new Error("assert() requires at least one argument");
1148
+ }
1149
+ const condition = this.exprParser.parse(args[0]);
1150
+ if (!condition) {
1151
+ throw new Error("Could not parse assert condition");
1152
+ }
1153
+ const message = args.length > 1 && args[1].type === "Literal" ? String(args[1].value) : void 0;
1154
+ return { kind: "assert", condition, message };
1155
+ }
1156
+ /**
1157
+ * Parses assignment expressions: x = 5;
1158
+ */
1159
+ parseAssignment(expr) {
1160
+ const left = expr.left;
1161
+ const right = expr.right;
1162
+ if (left.type !== "Identifier") {
1163
+ throw new Error("Assignment target must be an identifier");
1164
+ }
1165
+ const value = this.exprParser.parse(right);
1166
+ if (!value) {
1167
+ throw new Error("Could not parse assignment value");
1168
+ }
1169
+ const name = left.name;
1170
+ return {
1171
+ kind: "assignment",
1172
+ target: stripMutPrefix(name),
1173
+ value
1174
+ };
1175
+ }
1176
+ /**
1177
+ * Parses if statements: if (condition) { ... } else { ... }
1178
+ */
1179
+ parseIfStatement(node) {
1180
+ const condition = this.exprParser.parse(node.test);
1181
+ if (!condition) {
1182
+ throw new Error("Could not parse if condition");
1183
+ }
1184
+ const consequent = this.parseBlock(node.consequent);
1185
+ const alternate = node.alternate ? this.parseBlock(node.alternate) : void 0;
1186
+ return {
1187
+ kind: "if_statement",
1188
+ condition,
1189
+ consequent,
1190
+ alternate
1191
+ };
1192
+ }
1193
+ };
1194
+
1195
+ // src/infra/parser/ForLoopParser.ts
1196
+ var ForLoopParser = class {
1197
+ constructor(exprParser) {
1198
+ this.exprParser = exprParser;
1199
+ }
1200
+ /**
1201
+ * Parses a for statement into a circuit for_statement.
1202
+ * @param node The ForStatement AST node
1203
+ * @param parseBlock Function to parse the loop body
1204
+ */
1205
+ parse(node, parseBlock) {
1206
+ const { variable, start } = this.validateInit(node.init);
1207
+ const { end, inclusive } = this.validateTest(node.test, variable);
1208
+ this.validateUpdate(node.update, variable);
1209
+ const body = parseBlock(node.body);
1210
+ return {
1211
+ kind: "for_statement",
1212
+ variable,
1213
+ start,
1214
+ end,
1215
+ inclusive,
1216
+ body
1217
+ };
1218
+ }
1219
+ /**
1220
+ * Validates the for loop initializer.
1221
+ * Must be: `let i = start`
1222
+ */
1223
+ validateInit(init) {
1224
+ if (!init || init.type !== "VariableDeclaration") {
1225
+ throw new Error("For loop init must be a variable declaration (let i = start)");
1226
+ }
1227
+ const declaration = init.declarations[0];
1228
+ if (!declaration || declaration.id.type !== "Identifier") {
1229
+ throw new Error("For loop must declare a simple variable");
1230
+ }
1231
+ const variable = declaration.id.name;
1232
+ const startInit = declaration.init;
1233
+ if (!startInit) {
1234
+ throw new Error("For loop variable must have an initializer");
1235
+ }
1236
+ const start = this.exprParser.parse(startInit);
1237
+ if (!start) {
1238
+ throw new Error("Could not parse for loop start value");
1239
+ }
1240
+ return { variable, start };
1241
+ }
1242
+ /**
1243
+ * Validates the for loop test condition.
1244
+ * Must be: `i < end` or `i <= end`
1245
+ */
1246
+ validateTest(test, variable) {
1247
+ if (!test || test.type !== "BinaryExpression") {
1248
+ throw new Error("For loop test must be a comparison (i < end or i <= end)");
1249
+ }
1250
+ const testLeft = test.left;
1251
+ if (testLeft.type !== "Identifier" || testLeft.name !== variable) {
1252
+ throw new Error("For loop test must compare the loop variable");
1253
+ }
1254
+ const operator = test.operator;
1255
+ if (operator !== "<" && operator !== "<=") {
1256
+ throw new Error("For loop test must use < or <= operator");
1257
+ }
1258
+ const end = this.exprParser.parse(test.right);
1259
+ if (!end) {
1260
+ throw new Error("Could not parse for loop end value");
1261
+ }
1262
+ return { end, inclusive: operator === "<=" };
1263
+ }
1264
+ /**
1265
+ * Validates the for loop update expression.
1266
+ * Must be: `i++`, `++i`, or `i = i + 1`
1267
+ */
1268
+ validateUpdate(update, variable) {
1269
+ if (!update) {
1270
+ throw new Error("For loop must have an update expression");
1271
+ }
1272
+ if (!this.isSimpleIncrement(update, variable)) {
1273
+ throw new Error("For loop update must be i++ or i = i + 1 or ++i");
1274
+ }
1275
+ }
1276
+ /**
1277
+ * Checks if an expression is a simple increment of the variable.
1278
+ * Accepts: i++, ++i, i = i + 1
1279
+ */
1280
+ isSimpleIncrement(node, variable) {
1281
+ if (node.type === "UpdateExpression") {
1282
+ const arg = node.argument;
1283
+ return node.operator === "++" && arg.type === "Identifier" && arg.name === variable;
1284
+ }
1285
+ if (node.type === "AssignmentExpression") {
1286
+ const left = node.left;
1287
+ const right = node.right;
1288
+ if (left.type !== "Identifier" || left.name !== variable) {
1289
+ return false;
1290
+ }
1291
+ if (right.type === "BinaryExpression") {
1292
+ const binLeft = right.left;
1293
+ const binRight = right.right;
1294
+ return right.operator === "+" && binLeft.type === "Identifier" && binLeft.name === variable && binRight.type === "Literal" && binRight.value === 1;
1295
+ }
1296
+ }
1297
+ return false;
1298
+ }
1299
+ };
1300
+
1301
+ // src/infra/parser/AcornParser.ts
1302
+ var AcornParser = class {
1303
+ exprParser = new ExpressionParser();
1304
+ forLoopParser = new ForLoopParser(this.exprParser);
1305
+ stmtParser = new StatementParser(this.exprParser, this.forLoopParser);
1306
+ /**
1307
+ * Parses a circuit function into public/private parameters and statements.
1308
+ *
1309
+ * @param fn The circuit function with signature ([public], [private]) => { ... }
1310
+ * @param _publicInputs Public input values (used for validation, not parsing)
1311
+ * @param _privateInputs Private input values (used for validation, not parsing)
1312
+ */
1313
+ parse(fn, _publicInputs, _privateInputs) {
1314
+ const fnSource = fn.toString();
1315
+ const ast = acorn.parse(`(${fnSource})`, {
1316
+ ecmaVersion: 2022,
1317
+ sourceType: "module"
1318
+ });
1319
+ const fnNode = this.findFunctionNode(ast);
1320
+ const { publicParams, privateParams } = this.extractParameters(fnNode);
1321
+ const statements = this.parseBody(fnNode);
1322
+ return { publicParams, privateParams, statements };
1323
+ }
1324
+ /**
1325
+ * Finds the arrow function or function expression in the AST.
1326
+ */
1327
+ findFunctionNode(ast) {
1328
+ let fnNode = null;
1329
+ walk.simple(ast, {
1330
+ ArrowFunctionExpression(node) {
1331
+ fnNode = node;
1332
+ },
1333
+ FunctionExpression(node) {
1334
+ fnNode = node;
1335
+ }
1336
+ });
1337
+ if (!fnNode) {
1338
+ throw new Error("Could not find function in source");
1339
+ }
1340
+ return fnNode;
1341
+ }
1342
+ /**
1343
+ * Extracts public and private parameters from the function signature.
1344
+ * Expects pattern: ([pub1, pub2], [priv1, priv2]) => { ... }
1345
+ */
1346
+ extractParameters(fnNode) {
1347
+ const params = fnNode.params;
1348
+ if (params.length !== 2) {
1349
+ throw new Error(
1350
+ "Circuit function must have exactly 2 parameters: (publicArgs, privateArgs)"
1351
+ );
1352
+ }
1353
+ const publicParams = [];
1354
+ const privateParams = [];
1355
+ const pubParam = params[0];
1356
+ if (pubParam.type === "ArrayPattern") {
1357
+ pubParam.elements.forEach((elem, idx) => {
1358
+ if (elem && elem.type === "Identifier") {
1359
+ publicParams.push({ name: elem.name, index: idx });
1360
+ }
1361
+ });
1362
+ }
1363
+ const privParam = params[1];
1364
+ if (privParam.type === "ArrayPattern") {
1365
+ privParam.elements.forEach((elem, idx) => {
1366
+ if (elem && elem.type === "Identifier") {
1367
+ privateParams.push({ name: elem.name, index: idx });
1368
+ }
1369
+ });
1370
+ }
1371
+ return { publicParams, privateParams };
1372
+ }
1373
+ /**
1374
+ * Parses the function body into statements.
1375
+ */
1376
+ parseBody(fnNode) {
1377
+ const body = fnNode.body;
1378
+ const statements = [];
1379
+ if (body.type === "BlockStatement") {
1380
+ for (const stmt of body.body) {
1381
+ const parsed = this.stmtParser.parse(stmt);
1382
+ if (parsed) {
1383
+ statements.push(parsed);
1384
+ }
1385
+ }
1386
+ } else {
1387
+ const expr = this.exprParser.parse(body);
1388
+ if (expr) {
1389
+ statements.push({ kind: "assert", condition: expr });
1390
+ }
1391
+ }
1392
+ return statements;
1393
+ }
1394
+ };
1395
+
1396
+ // src/container.ts
1397
+ init_Barretenberg();
1398
+ init_ArkworksWasm();
1399
+ function createDefaultContainer() {
1400
+ return {
1401
+ parser: new AcornParser(),
1402
+ provingSystem: new Barretenberg()
1403
+ };
1404
+ }
1405
+ function createArkworksWasmContainer(config) {
1406
+ return {
1407
+ parser: new AcornParser(),
1408
+ provingSystem: new ArkworksWasm(config)
1409
+ };
1410
+ }
1411
+
1412
+ // src/application/services/NoirGenerator.ts
1413
+ function generateNoir(circuit) {
1414
+ const params = generateParams(circuit);
1415
+ const body = generateBody(circuit.statements);
1416
+ return `fn main(${params}) {
1417
+ ${body}
1418
+ }
1419
+ `;
1420
+ }
1421
+ function generateParams(circuit) {
1422
+ const allParams = [];
1423
+ for (const param of circuit.privateParams) {
1424
+ allParams.push(`${param.name}: Field`);
1425
+ }
1426
+ for (const param of circuit.publicParams) {
1427
+ allParams.push(`${param.name}: pub Field`);
1428
+ }
1429
+ return allParams.join(", ");
1430
+ }
1431
+ function generateBody(statements, indent = 1) {
1432
+ const lines = [];
1433
+ const indentStr = " ".repeat(indent);
1434
+ for (const stmt of statements) {
1435
+ const generated = generateStatement(stmt, indent);
1436
+ if (generated.includes("\n")) {
1437
+ lines.push(generated);
1438
+ } else {
1439
+ lines.push(`${indentStr}${generated}`);
1440
+ }
1441
+ }
1442
+ return lines.join("\n");
1443
+ }
1444
+ function generateStatement(stmt, indent = 1) {
1445
+ const indentStr = " ".repeat(indent);
1446
+ switch (stmt.kind) {
1447
+ case "assert": {
1448
+ const condition = generateExpr(stmt.condition);
1449
+ if (stmt.message) {
1450
+ return `assert(${condition}, "${stmt.message}");`;
1451
+ }
1452
+ return `assert(${condition});`;
1453
+ }
1454
+ case "variable_declaration": {
1455
+ const init = generateExpr(stmt.initializer);
1456
+ const mutKeyword = stmt.mutable ? "let mut" : "let";
1457
+ const typeStr = inferType(stmt.initializer);
1458
+ return `${mutKeyword} ${stmt.name}: ${typeStr} = ${init};`;
1459
+ }
1460
+ case "assignment": {
1461
+ const value = generateExpr(stmt.value);
1462
+ return `${stmt.target} = ${value};`;
1463
+ }
1464
+ case "if_statement": {
1465
+ const condition = generateExpr(stmt.condition);
1466
+ const consequentBody = generateBody(stmt.consequent, indent + 1);
1467
+ let result = `${indentStr}if ${condition} {
1468
+ ${consequentBody}
1469
+ ${indentStr}}`;
1470
+ if (stmt.alternate && stmt.alternate.length > 0) {
1471
+ const alternateBody = generateBody(stmt.alternate, indent + 1);
1472
+ result += ` else {
1473
+ ${alternateBody}
1474
+ ${indentStr}}`;
1475
+ }
1476
+ return result;
1477
+ }
1478
+ case "for_statement": {
1479
+ const start = generateExpr(stmt.start);
1480
+ const end = generateExpr(stmt.end);
1481
+ const rangeOp = stmt.inclusive ? "..=" : "..";
1482
+ const bodyContent = generateBody(stmt.body, indent + 1);
1483
+ return `${indentStr}for ${stmt.variable} in ${start}${rangeOp}${end} {
1484
+ ${bodyContent}
1485
+ ${indentStr}}`;
1486
+ }
1487
+ }
1488
+ }
1489
+ function generateExpr(expr) {
1490
+ switch (expr.kind) {
1491
+ case "identifier":
1492
+ return expr.name;
1493
+ case "literal":
1494
+ return formatLiteral(expr.value);
1495
+ case "binary": {
1496
+ const left = generateExpr(expr.left);
1497
+ const right = generateExpr(expr.right);
1498
+ return `${left} ${expr.operator} ${right}`;
1499
+ }
1500
+ case "unary": {
1501
+ const operand = generateExpr(expr.operand);
1502
+ if (expr.operand.kind === "binary") {
1503
+ return `${expr.operator}(${operand})`;
1504
+ }
1505
+ return `${expr.operator}${operand}`;
1506
+ }
1507
+ case "member": {
1508
+ const object = generateExpr(expr.object);
1509
+ const index = generateExpr(expr.index);
1510
+ return `${object}[${index}]`;
1511
+ }
1512
+ case "array_literal": {
1513
+ const elements = expr.elements.map((e) => generateExpr(e)).join(", ");
1514
+ return `[${elements}]`;
1515
+ }
1516
+ case "call": {
1517
+ const args = expr.args.map((a) => generateExpr(a)).join(", ");
1518
+ if (expr.method) {
1519
+ const callee2 = generateExpr(expr.callee);
1520
+ return `${callee2}.${expr.method}(${args})`;
1521
+ }
1522
+ const callee = generateExpr(expr.callee);
1523
+ return `${callee}(${args})`;
1524
+ }
1525
+ case "if_expr": {
1526
+ const condition = generateExpr(expr.condition);
1527
+ const consequent = generateExpr(expr.consequent);
1528
+ const alternate = generateExpr(expr.alternate);
1529
+ return `if ${condition} { ${consequent} } else { ${alternate} }`;
1530
+ }
1531
+ }
1532
+ }
1533
+ function formatLiteral(value) {
1534
+ if (typeof value === "bigint") {
1535
+ return value.toString();
1536
+ }
1537
+ if (typeof value === "number") {
1538
+ return value.toString();
1539
+ }
1540
+ if (typeof value === "string" && value.startsWith("0x")) {
1541
+ return value;
1542
+ }
1543
+ return `"${value}"`;
1544
+ }
1545
+ function inferType(expr) {
1546
+ switch (expr.kind) {
1547
+ case "array_literal":
1548
+ const elementType = expr.elements.length > 0 ? inferType(expr.elements[0]) : "Field";
1549
+ return `[${elementType}; ${expr.elements.length}]`;
1550
+ case "literal":
1551
+ if (typeof expr.value === "boolean") {
1552
+ return "bool";
1553
+ }
1554
+ return "Field";
1555
+ case "if_expr":
1556
+ return inferType(expr.consequent);
1557
+ default:
1558
+ return "Field";
1559
+ }
1560
+ }
1561
+
1562
+ // src/application/CreateProofUseCase.ts
1563
+ var CreateProofUseCase = class {
1564
+ constructor(deps) {
1565
+ this.deps = deps;
1566
+ }
1567
+ async execute(publicInputs, privateInputs, circuitFn) {
1568
+ const totalStart = performance.now();
1569
+ const timings = {
1570
+ parseMs: 0,
1571
+ generateMs: 0,
1572
+ compileMs: 0,
1573
+ witnessMs: 0,
1574
+ proofMs: 0,
1575
+ verifyMs: 0,
1576
+ totalMs: 0
1577
+ };
1578
+ const parseStart = performance.now();
1579
+ const parsed = this.deps.parser.parse(circuitFn, publicInputs, privateInputs);
1580
+ timings.parseMs = performance.now() - parseStart;
1581
+ const generateStart = performance.now();
1582
+ const noirCode = generateNoir(parsed);
1583
+ timings.generateMs = performance.now() - generateStart;
1584
+ const compileStart = performance.now();
1585
+ const circuit = await this.deps.provingSystem.compile(noirCode);
1586
+ timings.compileMs = performance.now() - compileStart;
1587
+ const toNoirInput = (val) => typeof val === "bigint" ? val.toString() : val;
1588
+ const inputs = {};
1589
+ for (const param of parsed.privateParams) {
1590
+ inputs[param.name] = toNoirInput(privateInputs[param.index]);
1591
+ }
1592
+ for (const param of parsed.publicParams) {
1593
+ inputs[param.name] = toNoirInput(publicInputs[param.index]);
1594
+ }
1595
+ const witnessStart = performance.now();
1596
+ const { proof, publicInputs: proofPublicInputs } = await this.deps.provingSystem.generateProof(circuit, inputs);
1597
+ const proofEnd = performance.now();
1598
+ const proveTime = proofEnd - witnessStart;
1599
+ timings.witnessMs = proveTime * 0.1;
1600
+ timings.proofMs = proveTime * 0.9;
1601
+ const verifyStart = performance.now();
1602
+ const verified = await this.deps.provingSystem.verifyProof(circuit, proof, proofPublicInputs);
1603
+ timings.verifyMs = performance.now() - verifyStart;
1604
+ timings.totalMs = performance.now() - totalStart;
1605
+ return {
1606
+ proof,
1607
+ publicInputs: proofPublicInputs,
1608
+ verified,
1609
+ noirCode,
1610
+ timings
1611
+ };
1612
+ }
1613
+ };
1614
+
1615
+ // src/providers/solana.ts
1616
+ var G1_SIZE2 = 64;
1617
+ var G2_SIZE2 = 128;
1618
+ var FIELD_SIZE = 32;
1619
+ var PROOF_SIZE = 256;
1620
+ var IZI_NOIR_PROGRAM_ID = "EYhRED7EuMyyVjx57aDXUD9h6ArnEKng64qtz8999KrS";
1621
+ function parseVerifyingKey(vkBase64, nrPubinputs) {
1622
+ const vkBytes = base64ToBytes(vkBase64);
1623
+ const expectedLen = G1_SIZE2 + G2_SIZE2 * 3 + G1_SIZE2 * (nrPubinputs + 1);
1624
+ if (vkBytes.length !== expectedLen) {
1625
+ throw new Error(
1626
+ `Invalid VK size: expected ${expectedLen} bytes for ${nrPubinputs} public inputs, got ${vkBytes.length}`
1627
+ );
1628
+ }
1629
+ let offset = 0;
1630
+ const alphaG1 = vkBytes.slice(offset, offset + G1_SIZE2);
1631
+ offset += G1_SIZE2;
1632
+ const betaG2 = vkBytes.slice(offset, offset + G2_SIZE2);
1633
+ offset += G2_SIZE2;
1634
+ const gammaG2 = vkBytes.slice(offset, offset + G2_SIZE2);
1635
+ offset += G2_SIZE2;
1636
+ const deltaG2 = vkBytes.slice(offset, offset + G2_SIZE2);
1637
+ offset += G2_SIZE2;
1638
+ const k = [];
1639
+ for (let i = 0; i <= nrPubinputs; i++) {
1640
+ k.push(vkBytes.slice(offset, offset + G1_SIZE2));
1641
+ offset += G1_SIZE2;
1642
+ }
1643
+ return { alphaG1, betaG2, gammaG2, deltaG2, k };
1644
+ }
1645
+ function parseProof(proofBase64) {
1646
+ const proofBytes = base64ToBytes(proofBase64);
1647
+ if (proofBytes.length !== PROOF_SIZE) {
1648
+ throw new Error(`Invalid proof size: expected ${PROOF_SIZE} bytes, got ${proofBytes.length}`);
1649
+ }
1650
+ return {
1651
+ a: proofBytes.slice(0, G1_SIZE2),
1652
+ b: proofBytes.slice(G1_SIZE2, G1_SIZE2 + G2_SIZE2),
1653
+ c: proofBytes.slice(G1_SIZE2 + G2_SIZE2, PROOF_SIZE)
1654
+ };
1655
+ }
1656
+ function parsePublicInputs(inputs) {
1657
+ return inputs.map((input) => {
1658
+ if (input.startsWith("0x")) {
1659
+ const hex2 = input.slice(2).padStart(64, "0");
1660
+ return hexToBytes2(hex2);
1661
+ }
1662
+ const num = BigInt(input);
1663
+ const hex = num.toString(16).padStart(64, "0");
1664
+ return hexToBytes2(hex);
1665
+ });
1666
+ }
1667
+ function calculateVkAccountSize(nrPubinputs) {
1668
+ const fixedSize = 8 + 32 + 1 + G1_SIZE2 + G2_SIZE2 * 3 + 4;
1669
+ return fixedSize + (nrPubinputs + 1) * G1_SIZE2;
1670
+ }
1671
+ function calculateVkAccountRent(nrPubinputs, rentExemptionPerByte = 6960) {
1672
+ const size = calculateVkAccountSize(nrPubinputs);
1673
+ return size * rentExemptionPerByte;
1674
+ }
1675
+ function base64ToBytes(base64) {
1676
+ if (typeof atob === "function") {
1677
+ const binary = atob(base64);
1678
+ const bytes = new Uint8Array(binary.length);
1679
+ for (let i = 0; i < binary.length; i++) {
1680
+ bytes[i] = binary.charCodeAt(i);
1681
+ }
1682
+ return bytes;
1683
+ }
1684
+ return new Uint8Array(Buffer.from(base64, "base64"));
1685
+ }
1686
+ function hexToBytes2(hex) {
1687
+ const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
1688
+ const bytes = new Uint8Array(cleanHex.length / 2);
1689
+ for (let i = 0; i < bytes.length; i++) {
1690
+ bytes[i] = parseInt(cleanHex.substring(i * 2, i * 2 + 2), 16);
1691
+ }
1692
+ return bytes;
1693
+ }
1694
+ function buildInitVkFromBytesData(nrPubinputs, vkBytes) {
1695
+ const discriminator = new Uint8Array([
1696
+ 166,
1697
+ 58,
1698
+ 82,
1699
+ 247,
1700
+ 19,
1701
+ 129,
1702
+ 138,
1703
+ 59
1704
+ ]);
1705
+ const vkLen = new Uint8Array(4);
1706
+ new DataView(vkLen.buffer).setUint32(0, vkBytes.length, true);
1707
+ const data = new Uint8Array(discriminator.length + 1 + 4 + vkBytes.length);
1708
+ let offset = 0;
1709
+ data.set(discriminator, offset);
1710
+ offset += discriminator.length;
1711
+ data[offset] = nrPubinputs;
1712
+ offset += 1;
1713
+ data.set(vkLen, offset);
1714
+ offset += 4;
1715
+ data.set(vkBytes, offset);
1716
+ return data;
1717
+ }
1718
+ function buildVerifyProofData(proofBytes, publicInputs) {
1719
+ const discriminator = new Uint8Array([
1720
+ 30,
1721
+ 8,
1722
+ 242,
1723
+ 54,
1724
+ 68,
1725
+ 154,
1726
+ 75,
1727
+ 92
1728
+ ]);
1729
+ if (proofBytes.length !== PROOF_SIZE) {
1730
+ throw new Error(`Invalid proof size: expected ${PROOF_SIZE}, got ${proofBytes.length}`);
1731
+ }
1732
+ const proofVecLen = 4 + proofBytes.length;
1733
+ const inputsVecLen = 4 + publicInputs.length * FIELD_SIZE;
1734
+ const totalSize = discriminator.length + proofVecLen + inputsVecLen;
1735
+ const data = new Uint8Array(totalSize);
1736
+ let offset = 0;
1737
+ data.set(discriminator, offset);
1738
+ offset += discriminator.length;
1739
+ new DataView(data.buffer).setUint32(offset, proofBytes.length, true);
1740
+ offset += 4;
1741
+ data.set(proofBytes, offset);
1742
+ offset += proofBytes.length;
1743
+ new DataView(data.buffer).setUint32(offset, publicInputs.length, true);
1744
+ offset += 4;
1745
+ for (const input of publicInputs) {
1746
+ if (input.length !== FIELD_SIZE) {
1747
+ throw new Error(`Invalid public input size: expected ${FIELD_SIZE}, got ${input.length}`);
1748
+ }
1749
+ data.set(input, offset);
1750
+ offset += FIELD_SIZE;
1751
+ }
1752
+ return data;
1753
+ }
1754
+
1755
+ // src/solana/TransactionBuilder.ts
1756
+ var SYSTEM_PROGRAM_ID = "11111111111111111111111111111111";
1757
+ var COMPUTE_BUDGET_PROGRAM_ID = "ComputeBudget111111111111111111111111111111";
1758
+ var SolanaTransactionBuilder = class {
1759
+ programId;
1760
+ computeUnits;
1761
+ priorityFee;
1762
+ constructor(config = {}) {
1763
+ this.programId = config.programId ?? IZI_NOIR_PROGRAM_ID;
1764
+ this.computeUnits = config.computeUnits ?? 4e5;
1765
+ this.priorityFee = config.priorityFee ?? 0;
1766
+ }
1767
+ /**
1768
+ * Builds the instruction data for initializing a VK account.
1769
+ *
1770
+ * @param solanaProofData - Proof data from `izi.proveForSolana()`
1771
+ * @param accounts - Account public keys
1772
+ * @returns Instruction data ready for transaction building
1773
+ *
1774
+ * @example
1775
+ * ```typescript
1776
+ * const initInstruction = builder.buildInitVkInstruction(solanaProofData, {
1777
+ * vkAccount: vkKeypair.publicKey.toBase58(),
1778
+ * authority: wallet.publicKey.toBase58(),
1779
+ * payer: wallet.publicKey.toBase58(),
1780
+ * });
1781
+ * ```
1782
+ */
1783
+ buildInitVkInstruction(solanaProofData, accounts) {
1784
+ const data = buildInitVkFromBytesData(
1785
+ solanaProofData.verifyingKey.nrPublicInputs,
1786
+ solanaProofData.verifyingKey.bytes
1787
+ );
1788
+ return {
1789
+ data,
1790
+ programId: this.programId,
1791
+ keys: [
1792
+ { pubkey: accounts.vkAccount, isSigner: true, isWritable: true },
1793
+ { pubkey: accounts.authority, isSigner: true, isWritable: false },
1794
+ { pubkey: accounts.payer, isSigner: true, isWritable: true },
1795
+ { pubkey: SYSTEM_PROGRAM_ID, isSigner: false, isWritable: false }
1796
+ ]
1797
+ };
1798
+ }
1799
+ /**
1800
+ * Builds the instruction data for verifying a proof.
1801
+ *
1802
+ * @param proofBytes - 256-byte Groth16 proof
1803
+ * @param publicInputs - Array of 32-byte public inputs
1804
+ * @param accounts - Account public keys
1805
+ * @returns Instruction data ready for transaction building
1806
+ *
1807
+ * @example
1808
+ * ```typescript
1809
+ * const verifyInstruction = builder.buildVerifyProofInstruction(
1810
+ * solanaProofData.proof.bytes,
1811
+ * solanaProofData.publicInputs.bytes,
1812
+ * { vkAccount: vkAccountPubkey.toBase58() }
1813
+ * );
1814
+ * ```
1815
+ */
1816
+ buildVerifyProofInstruction(proofBytes, publicInputs, accounts) {
1817
+ const data = buildVerifyProofData(proofBytes, publicInputs);
1818
+ return {
1819
+ data,
1820
+ programId: this.programId,
1821
+ keys: [
1822
+ { pubkey: accounts.vkAccount, isSigner: false, isWritable: false }
1823
+ ]
1824
+ };
1825
+ }
1826
+ /**
1827
+ * Builds the instruction data for closing a VK account.
1828
+ *
1829
+ * @param accounts - Account public keys
1830
+ * @returns Instruction data ready for transaction building
1831
+ */
1832
+ buildCloseVkInstruction(accounts) {
1833
+ const discriminator = new Uint8Array([
1834
+ 154,
1835
+ 71,
1836
+ 2,
1837
+ 43,
1838
+ 135,
1839
+ 151,
1840
+ 132,
1841
+ 74
1842
+ ]);
1843
+ return {
1844
+ data: discriminator,
1845
+ programId: this.programId,
1846
+ keys: [
1847
+ { pubkey: accounts.vkAccount, isSigner: false, isWritable: true },
1848
+ { pubkey: accounts.authority, isSigner: true, isWritable: true }
1849
+ ]
1850
+ };
1851
+ }
1852
+ /**
1853
+ * Builds a compute budget instruction to set compute unit limit.
1854
+ *
1855
+ * @param units - Number of compute units (default: configured value)
1856
+ * @returns Instruction data
1857
+ */
1858
+ buildSetComputeUnitLimitInstruction(units) {
1859
+ const cu = units ?? this.computeUnits;
1860
+ const data = new Uint8Array(5);
1861
+ data[0] = 2;
1862
+ new DataView(data.buffer).setUint32(1, cu, true);
1863
+ return {
1864
+ data,
1865
+ programId: COMPUTE_BUDGET_PROGRAM_ID,
1866
+ keys: []
1867
+ };
1868
+ }
1869
+ /**
1870
+ * Builds a compute budget instruction to set priority fee.
1871
+ *
1872
+ * @param microLamports - Priority fee in microLamports per CU
1873
+ * @returns Instruction data
1874
+ */
1875
+ buildSetComputeUnitPriceInstruction(microLamports) {
1876
+ const fee = microLamports ?? this.priorityFee;
1877
+ const data = new Uint8Array(9);
1878
+ data[0] = 3;
1879
+ const view = new DataView(data.buffer);
1880
+ view.setBigUint64(1, BigInt(fee), true);
1881
+ return {
1882
+ data,
1883
+ programId: COMPUTE_BUDGET_PROGRAM_ID,
1884
+ keys: []
1885
+ };
1886
+ }
1887
+ /**
1888
+ * Builds all instructions needed to initialize a VK and verify a proof.
1889
+ *
1890
+ * This is a convenience method that combines:
1891
+ * - Compute budget instructions (if configured)
1892
+ * - Init VK instruction
1893
+ * - Verify proof instruction
1894
+ *
1895
+ * @param solanaProofData - Proof data from `izi.proveForSolana()`
1896
+ * @param vkAccountPubkey - Public key for the new VK account
1897
+ * @param authorityPubkey - Authority for the VK account
1898
+ * @param payerPubkey - Payer for the transaction
1899
+ * @returns All instruction data and metadata
1900
+ *
1901
+ * @example
1902
+ * ```typescript
1903
+ * const result = builder.buildInitAndVerifyInstructions(
1904
+ * solanaProofData,
1905
+ * vkKeypair.publicKey.toBase58(),
1906
+ * wallet.publicKey.toBase58(),
1907
+ * wallet.publicKey.toBase58()
1908
+ * );
1909
+ *
1910
+ * // Use with @solana/web3.js:
1911
+ * const transaction = new Transaction();
1912
+ * if (result.computeBudget) {
1913
+ * transaction.add(toTransactionInstruction(result.computeBudget));
1914
+ * }
1915
+ * transaction.add(toTransactionInstruction(result.initVk));
1916
+ * // ... sign and send
1917
+ * ```
1918
+ */
1919
+ buildInitAndVerifyInstructions(solanaProofData, vkAccountPubkey, authorityPubkey, payerPubkey) {
1920
+ const result = {
1921
+ initVk: this.buildInitVkInstruction(solanaProofData, {
1922
+ vkAccount: vkAccountPubkey,
1923
+ authority: authorityPubkey,
1924
+ payer: payerPubkey
1925
+ }),
1926
+ verifyProof: this.buildVerifyProofInstruction(
1927
+ solanaProofData.proof.bytes,
1928
+ solanaProofData.publicInputs.bytes,
1929
+ { vkAccount: vkAccountPubkey }
1930
+ ),
1931
+ rentLamports: solanaProofData.estimatedRent,
1932
+ accountSize: solanaProofData.accountSize
1933
+ };
1934
+ if (this.computeUnits > 0) {
1935
+ result.computeBudget = this.buildSetComputeUnitLimitInstruction();
1936
+ }
1937
+ if (this.priorityFee > 0) {
1938
+ result.priorityFee = this.buildSetComputeUnitPriceInstruction();
1939
+ }
1940
+ return result;
1941
+ }
1942
+ /**
1943
+ * Validates that SolanaProofData has the correct format.
1944
+ *
1945
+ * @param data - Proof data to validate
1946
+ * @throws Error if validation fails
1947
+ */
1948
+ validateSolanaProofData(data) {
1949
+ if (data.proof.bytes.length !== PROOF_SIZE) {
1950
+ throw new Error(
1951
+ `Invalid proof size: expected ${PROOF_SIZE} bytes, got ${data.proof.bytes.length}`
1952
+ );
1953
+ }
1954
+ const expectedVkSize = G1_SIZE2 + G2_SIZE2 * 3 + G1_SIZE2 * (data.verifyingKey.nrPublicInputs + 1);
1955
+ if (data.verifyingKey.bytes.length !== expectedVkSize) {
1956
+ throw new Error(
1957
+ `Invalid VK size: expected ${expectedVkSize} bytes for ${data.verifyingKey.nrPublicInputs} public inputs, got ${data.verifyingKey.bytes.length}`
1958
+ );
1959
+ }
1960
+ for (let i = 0; i < data.publicInputs.bytes.length; i++) {
1961
+ if (data.publicInputs.bytes[i].length !== FIELD_SIZE) {
1962
+ throw new Error(
1963
+ `Invalid public input ${i} size: expected ${FIELD_SIZE} bytes, got ${data.publicInputs.bytes[i].length}`
1964
+ );
1965
+ }
1966
+ }
1967
+ if (data.publicInputs.bytes.length !== data.verifyingKey.nrPublicInputs) {
1968
+ throw new Error(
1969
+ `Public inputs count mismatch: VK expects ${data.verifyingKey.nrPublicInputs}, got ${data.publicInputs.bytes.length}`
1970
+ );
1971
+ }
1972
+ }
1973
+ /**
1974
+ * Gets the program ID being used.
1975
+ */
1976
+ getProgramId() {
1977
+ return this.programId;
1978
+ }
1979
+ /**
1980
+ * Gets the configured compute units.
1981
+ */
1982
+ getComputeUnits() {
1983
+ return this.computeUnits;
1984
+ }
1985
+ /**
1986
+ * Gets the configured priority fee.
1987
+ */
1988
+ getPriorityFee() {
1989
+ return this.priorityFee;
1990
+ }
1991
+ };
1992
+
1993
+ // src/deployment/VkDeploymentManager.ts
1994
+ var NETWORK_ENDPOINTS = {
1995
+ "mainnet-beta": "https://api.mainnet-beta.solana.com",
1996
+ devnet: "https://api.devnet.solana.com",
1997
+ testnet: "https://api.testnet.solana.com",
1998
+ localnet: "http://localhost:8899"
1999
+ };
2000
+ var VkDeploymentManager = class {
2001
+ config;
2002
+ deployments;
2003
+ builder;
2004
+ dirty = false;
2005
+ constructor(config) {
2006
+ this.config = {
2007
+ network: config.network,
2008
+ rpcEndpoint: config.rpcEndpoint ?? NETWORK_ENDPOINTS[config.network],
2009
+ configDir: config.configDir ?? ".izi-noir",
2010
+ programId: config.programId ?? "",
2011
+ computeUnits: config.computeUnits ?? 4e5
2012
+ };
2013
+ this.deployments = /* @__PURE__ */ new Map();
2014
+ this.builder = new SolanaTransactionBuilder({
2015
+ programId: this.config.programId || void 0,
2016
+ computeUnits: this.config.computeUnits
2017
+ });
2018
+ }
2019
+ /**
2020
+ * Loads deployment state from disk.
2021
+ *
2022
+ * In browser environments, this is a no-op.
2023
+ * In Node.js, reads from {configDir}/deployments.json
2024
+ */
2025
+ async load() {
2026
+ }
2027
+ /**
2028
+ * Loads deployment state from a JSON object.
2029
+ */
2030
+ loadFromJson(state) {
2031
+ this.deployments.clear();
2032
+ for (const deployment of state.deployments) {
2033
+ if (deployment.network === this.config.network) {
2034
+ const key = this.makeDeploymentKey(deployment.circuitId, deployment.vkHash);
2035
+ this.deployments.set(key, deployment);
2036
+ }
2037
+ }
2038
+ this.dirty = false;
2039
+ }
2040
+ /**
2041
+ * Saves deployment state.
2042
+ *
2043
+ * Returns the state object for custom persistence.
2044
+ */
2045
+ async save() {
2046
+ const state = this.toJson();
2047
+ this.dirty = false;
2048
+ return state;
2049
+ }
2050
+ /**
2051
+ * Exports deployment state to JSON.
2052
+ */
2053
+ toJson() {
2054
+ return {
2055
+ version: "1.0",
2056
+ deployments: Array.from(this.deployments.values())
2057
+ };
2058
+ }
2059
+ /**
2060
+ * Ensures a VK is deployed, skipping if already exists.
2061
+ *
2062
+ * @returns Deployment result with VK account address
2063
+ */
2064
+ async ensureDeployed(options) {
2065
+ const { circuitName, solanaProofData, authority, payer, forceRedeploy } = options;
2066
+ const vkHash = await this.hashVkBytes(solanaProofData.verifyingKey.bytes);
2067
+ const deploymentKey = this.makeDeploymentKey(circuitName, vkHash);
2068
+ const existing = this.deployments.get(deploymentKey);
2069
+ if (existing && !forceRedeploy) {
2070
+ return {
2071
+ deployed: false,
2072
+ vkAccount: existing.vkAccount,
2073
+ deployment: existing
2074
+ };
2075
+ }
2076
+ const vkAccountPubkey = this.generateVkAccountPlaceholder();
2077
+ const instructions = [];
2078
+ instructions.push(this.builder.buildSetComputeUnitLimitInstruction());
2079
+ const initVk = this.builder.buildInitVkInstruction(solanaProofData, {
2080
+ vkAccount: vkAccountPubkey,
2081
+ authority,
2082
+ payer
2083
+ });
2084
+ instructions.push(initVk);
2085
+ const signers = [
2086
+ { pubkey: vkAccountPubkey, isNewKeypair: true, role: "vkAccount" },
2087
+ { pubkey: authority, isNewKeypair: false, role: "authority" }
2088
+ ];
2089
+ if (payer !== authority) {
2090
+ signers.push({ pubkey: payer, isNewKeypair: false, role: "payer" });
2091
+ }
2092
+ const txSignature = await options.sendTransaction(instructions, signers);
2093
+ const deployment = {
2094
+ circuitId: circuitName,
2095
+ vkAccount: vkAccountPubkey,
2096
+ authority,
2097
+ deployedAt: (/* @__PURE__ */ new Date()).toISOString(),
2098
+ txSignature,
2099
+ network: this.config.network,
2100
+ vkHash,
2101
+ nrPublicInputs: solanaProofData.verifyingKey.nrPublicInputs
2102
+ };
2103
+ this.deployments.set(deploymentKey, deployment);
2104
+ this.dirty = true;
2105
+ return {
2106
+ deployed: true,
2107
+ vkAccount: vkAccountPubkey,
2108
+ txSignature,
2109
+ deployment
2110
+ };
2111
+ }
2112
+ /**
2113
+ * Gets deployment by circuit name.
2114
+ */
2115
+ getDeployment(circuitName) {
2116
+ for (const [key, deployment] of this.deployments) {
2117
+ if (deployment.circuitId === circuitName) {
2118
+ return deployment;
2119
+ }
2120
+ }
2121
+ return void 0;
2122
+ }
2123
+ /**
2124
+ * Gets deployment by VK hash.
2125
+ */
2126
+ getDeploymentByVkHash(vkHash) {
2127
+ for (const deployment of this.deployments.values()) {
2128
+ if (deployment.vkHash === vkHash) {
2129
+ return deployment;
2130
+ }
2131
+ }
2132
+ return void 0;
2133
+ }
2134
+ /**
2135
+ * Gets all deployments.
2136
+ */
2137
+ getAllDeployments() {
2138
+ return Array.from(this.deployments.values());
2139
+ }
2140
+ /**
2141
+ * Checks if there are unsaved changes.
2142
+ */
2143
+ isDirty() {
2144
+ return this.dirty;
2145
+ }
2146
+ /**
2147
+ * Gets the RPC endpoint.
2148
+ */
2149
+ getRpcEndpoint() {
2150
+ return this.config.rpcEndpoint;
2151
+ }
2152
+ /**
2153
+ * Gets the network.
2154
+ */
2155
+ getNetwork() {
2156
+ return this.config.network;
2157
+ }
2158
+ /**
2159
+ * Prepares instructions for deployment without sending.
2160
+ *
2161
+ * Useful when you need to combine with other instructions
2162
+ * or use a specific signing flow.
2163
+ */
2164
+ prepareDeployment(solanaProofData, accounts) {
2165
+ const instructions = [];
2166
+ instructions.push(this.builder.buildSetComputeUnitLimitInstruction());
2167
+ instructions.push(
2168
+ this.builder.buildInitVkInstruction(solanaProofData, {
2169
+ vkAccount: accounts.vkAccount,
2170
+ authority: accounts.authority,
2171
+ payer: accounts.payer
2172
+ })
2173
+ );
2174
+ const signers = [
2175
+ { pubkey: accounts.vkAccount, isNewKeypair: true, role: "vkAccount" },
2176
+ { pubkey: accounts.authority, isNewKeypair: false, role: "authority" }
2177
+ ];
2178
+ if (accounts.payer !== accounts.authority) {
2179
+ signers.push({ pubkey: accounts.payer, isNewKeypair: false, role: "payer" });
2180
+ }
2181
+ return {
2182
+ instructions,
2183
+ signers,
2184
+ rentLamports: solanaProofData.estimatedRent
2185
+ };
2186
+ }
2187
+ /**
2188
+ * Records an external deployment (made outside this manager).
2189
+ */
2190
+ recordDeployment(deployment) {
2191
+ const key = this.makeDeploymentKey(deployment.circuitId, deployment.vkHash);
2192
+ this.deployments.set(key, deployment);
2193
+ this.dirty = true;
2194
+ }
2195
+ /**
2196
+ * Removes a deployment record.
2197
+ */
2198
+ removeDeployment(circuitName) {
2199
+ for (const [key, deployment] of this.deployments) {
2200
+ if (deployment.circuitId === circuitName) {
2201
+ this.deployments.delete(key);
2202
+ this.dirty = true;
2203
+ return true;
2204
+ }
2205
+ }
2206
+ return false;
2207
+ }
2208
+ // Private helpers
2209
+ makeDeploymentKey(circuitId, vkHash) {
2210
+ return `${circuitId}:${vkHash.slice(0, 16)}`;
2211
+ }
2212
+ async hashVkBytes(bytes) {
2213
+ if (typeof crypto !== "undefined" && crypto.subtle) {
2214
+ const hashBuffer = await crypto.subtle.digest("SHA-256", bytes);
2215
+ const hashArray = new Uint8Array(hashBuffer);
2216
+ return Array.from(hashArray).map((b) => b.toString(16).padStart(2, "0")).join("");
2217
+ }
2218
+ let hash = 0;
2219
+ for (let i = 0; i < bytes.length; i++) {
2220
+ hash = (hash << 5) - hash + bytes[i] | 0;
2221
+ }
2222
+ return Math.abs(hash).toString(16).padStart(8, "0");
2223
+ }
2224
+ generateVkAccountPlaceholder() {
2225
+ return "PENDING_VK_ACCOUNT_KEYPAIR";
2226
+ }
2227
+ };
2228
+ async function createNodeVkDeploymentManager(config) {
2229
+ const manager = new VkDeploymentManager(config);
2230
+ await manager.load();
2231
+ return manager;
2232
+ }
2233
+
2234
+ // src/registry/CircuitRegistry.ts
2235
+ var CircuitRegistry = class {
2236
+ circuits = /* @__PURE__ */ new Map();
2237
+ /**
2238
+ * Registers a new circuit.
2239
+ *
2240
+ * @param definition - Circuit definition with metadata
2241
+ * @returns The registered circuit with computed fields
2242
+ * @throws Error if circuit with same name and version exists
2243
+ */
2244
+ register(definition) {
2245
+ const { name, version } = definition;
2246
+ if (!/^\d+\.\d+\.\d+/.test(version)) {
2247
+ throw new Error(
2248
+ `Invalid version format: ${version}. Use semantic versioning (e.g., '1.0.0')`
2249
+ );
2250
+ }
2251
+ if (typeof definition.jsCircuit !== "function") {
2252
+ throw new Error("jsCircuit must be a function");
2253
+ }
2254
+ const existing = this.circuits.get(name) ?? [];
2255
+ if (existing.some((c) => c.version === version)) {
2256
+ throw new Error(
2257
+ `Circuit '${name}' version ${version} already registered. Use a new version.`
2258
+ );
2259
+ }
2260
+ const functionHash = this.hashFunction(definition.jsCircuit);
2261
+ const registered = {
2262
+ ...definition,
2263
+ registeredAt: /* @__PURE__ */ new Date(),
2264
+ id: `${name}@${version}`,
2265
+ functionHash
2266
+ };
2267
+ existing.push(registered);
2268
+ existing.sort((a, b) => this.compareVersions(b.version, a.version));
2269
+ this.circuits.set(name, existing);
2270
+ return registered;
2271
+ }
2272
+ /**
2273
+ * Gets a circuit by name.
2274
+ *
2275
+ * @param name - Circuit name
2276
+ * @param options - Lookup options (version, etc.)
2277
+ * @returns The circuit or undefined if not found
2278
+ */
2279
+ get(name, options) {
2280
+ const versions = this.circuits.get(name);
2281
+ if (!versions || versions.length === 0) {
2282
+ return void 0;
2283
+ }
2284
+ if (options?.version) {
2285
+ return versions.find((c) => c.version === options.version);
2286
+ }
2287
+ return versions[0];
2288
+ }
2289
+ /**
2290
+ * Gets all versions of a circuit.
2291
+ *
2292
+ * @param name - Circuit name
2293
+ * @returns Array of all registered versions
2294
+ */
2295
+ getVersions(name) {
2296
+ return this.circuits.get(name) ?? [];
2297
+ }
2298
+ /**
2299
+ * Checks if a circuit exists.
2300
+ *
2301
+ * @param name - Circuit name
2302
+ * @param version - Optional specific version
2303
+ */
2304
+ has(name, version) {
2305
+ const circuit = this.get(name, version ? { version } : void 0);
2306
+ return circuit !== void 0;
2307
+ }
2308
+ /**
2309
+ * Gets all registered circuit names.
2310
+ */
2311
+ names() {
2312
+ return Array.from(this.circuits.keys());
2313
+ }
2314
+ /**
2315
+ * Gets all registered circuits.
2316
+ */
2317
+ all() {
2318
+ const result = [];
2319
+ for (const versions of this.circuits.values()) {
2320
+ result.push(...versions);
2321
+ }
2322
+ return result;
2323
+ }
2324
+ /**
2325
+ * Searches circuits by tag.
2326
+ *
2327
+ * @param tag - Tag to search for
2328
+ * @returns Circuits with matching tag
2329
+ */
2330
+ findByTag(tag) {
2331
+ const result = [];
2332
+ for (const versions of this.circuits.values()) {
2333
+ for (const circuit of versions) {
2334
+ if (circuit.tags?.includes(tag)) {
2335
+ result.push(circuit);
2336
+ }
2337
+ }
2338
+ }
2339
+ return result;
2340
+ }
2341
+ /**
2342
+ * Removes a circuit from the registry.
2343
+ *
2344
+ * @param name - Circuit name
2345
+ * @param version - Optional specific version (removes all if not specified)
2346
+ * @returns true if circuit was removed
2347
+ */
2348
+ remove(name, version) {
2349
+ if (!version) {
2350
+ return this.circuits.delete(name);
2351
+ }
2352
+ const versions = this.circuits.get(name);
2353
+ if (!versions) return false;
2354
+ const index = versions.findIndex((c) => c.version === version);
2355
+ if (index === -1) return false;
2356
+ versions.splice(index, 1);
2357
+ if (versions.length === 0) {
2358
+ this.circuits.delete(name);
2359
+ }
2360
+ return true;
2361
+ }
2362
+ /**
2363
+ * Exports the registry to a serializable format.
2364
+ */
2365
+ export() {
2366
+ const circuits = [];
2367
+ for (const [name, versions] of this.circuits) {
2368
+ for (const circuit of versions) {
2369
+ circuits.push({
2370
+ name: circuit.name,
2371
+ version: circuit.version,
2372
+ description: circuit.description,
2373
+ publicInputs: circuit.publicInputs,
2374
+ privateInputs: circuit.privateInputs,
2375
+ tags: circuit.tags,
2376
+ author: circuit.author,
2377
+ license: circuit.license,
2378
+ registeredAt: circuit.registeredAt.toISOString(),
2379
+ functionHash: circuit.functionHash
2380
+ // Note: jsCircuit is not serializable
2381
+ });
2382
+ }
2383
+ }
2384
+ return {
2385
+ version: "1.0",
2386
+ exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
2387
+ circuits
2388
+ };
2389
+ }
2390
+ /**
2391
+ * Generates documentation for a circuit.
2392
+ *
2393
+ * @param name - Circuit name
2394
+ * @returns Markdown documentation
2395
+ */
2396
+ generateDocs(name) {
2397
+ const circuit = this.get(name);
2398
+ if (!circuit) {
2399
+ return `Circuit '${name}' not found.`;
2400
+ }
2401
+ const lines = [
2402
+ `# ${circuit.name}`,
2403
+ "",
2404
+ `**Version:** ${circuit.version}`
2405
+ ];
2406
+ if (circuit.description) {
2407
+ lines.push("", circuit.description);
2408
+ }
2409
+ if (circuit.author) {
2410
+ lines.push("", `**Author:** ${circuit.author}`);
2411
+ }
2412
+ if (circuit.license) {
2413
+ lines.push(`**License:** ${circuit.license}`);
2414
+ }
2415
+ if (circuit.tags && circuit.tags.length > 0) {
2416
+ lines.push("", `**Tags:** ${circuit.tags.join(", ")}`);
2417
+ }
2418
+ lines.push("", "## Public Inputs", "");
2419
+ if (circuit.publicInputs.length === 0) {
2420
+ lines.push("None");
2421
+ } else {
2422
+ lines.push("| Name | Type | Description |", "|------|------|-------------|");
2423
+ for (const input of circuit.publicInputs) {
2424
+ lines.push(`| ${input.name} | ${input.type} | ${input.description ?? "-"} |`);
2425
+ }
2426
+ }
2427
+ lines.push("", "## Private Inputs", "");
2428
+ if (circuit.privateInputs.length === 0) {
2429
+ lines.push("None");
2430
+ } else {
2431
+ lines.push("| Name | Type | Description |", "|------|------|-------------|");
2432
+ for (const input of circuit.privateInputs) {
2433
+ lines.push(`| ${input.name} | ${input.type} | ${input.description ?? "-"} |`);
2434
+ }
2435
+ }
2436
+ lines.push("", "## Circuit Function", "", "```javascript", circuit.jsCircuit.toString(), "```");
2437
+ return lines.join("\n");
2438
+ }
2439
+ /**
2440
+ * Validates circuit inputs against the definition.
2441
+ *
2442
+ * @param name - Circuit name
2443
+ * @param publicInputs - Public inputs to validate
2444
+ * @param privateInputs - Private inputs to validate
2445
+ * @throws Error if validation fails
2446
+ */
2447
+ validateInputs(name, publicInputs, privateInputs) {
2448
+ const circuit = this.get(name);
2449
+ if (!circuit) {
2450
+ throw new Error(`Circuit '${name}' not found`);
2451
+ }
2452
+ if (publicInputs.length !== circuit.publicInputs.length) {
2453
+ throw new Error(
2454
+ `Expected ${circuit.publicInputs.length} public inputs, got ${publicInputs.length}`
2455
+ );
2456
+ }
2457
+ if (privateInputs.length !== circuit.privateInputs.length) {
2458
+ throw new Error(
2459
+ `Expected ${circuit.privateInputs.length} private inputs, got ${privateInputs.length}`
2460
+ );
2461
+ }
2462
+ for (let i = 0; i < publicInputs.length; i++) {
2463
+ this.validateInput(
2464
+ publicInputs[i],
2465
+ circuit.publicInputs[i],
2466
+ `public input '${circuit.publicInputs[i].name}'`
2467
+ );
2468
+ }
2469
+ for (let i = 0; i < privateInputs.length; i++) {
2470
+ this.validateInput(
2471
+ privateInputs[i],
2472
+ circuit.privateInputs[i],
2473
+ `private input '${circuit.privateInputs[i].name}'`
2474
+ );
2475
+ }
2476
+ }
2477
+ // Private helpers
2478
+ hashFunction(fn) {
2479
+ const str = fn.toString();
2480
+ let hash = 0;
2481
+ for (let i = 0; i < str.length; i++) {
2482
+ hash = (hash << 5) - hash + str.charCodeAt(i) | 0;
2483
+ }
2484
+ return Math.abs(hash).toString(16).padStart(8, "0");
2485
+ }
2486
+ compareVersions(a, b) {
2487
+ const partsA = a.split(".").map((n) => parseInt(n, 10));
2488
+ const partsB = b.split(".").map((n) => parseInt(n, 10));
2489
+ for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {
2490
+ const numA = partsA[i] ?? 0;
2491
+ const numB = partsB[i] ?? 0;
2492
+ if (numA > numB) return 1;
2493
+ if (numA < numB) return -1;
2494
+ }
2495
+ return 0;
2496
+ }
2497
+ validateInput(value, def, location) {
2498
+ switch (def.type) {
2499
+ case "bool":
2500
+ if (typeof value !== "boolean" && value !== 0 && value !== 1) {
2501
+ throw new Error(`${location}: expected boolean, got ${typeof value}`);
2502
+ }
2503
+ break;
2504
+ case "Field":
2505
+ case "u8":
2506
+ case "u16":
2507
+ case "u32":
2508
+ case "u64":
2509
+ if (typeof value !== "number" && typeof value !== "bigint") {
2510
+ throw new Error(`${location}: expected number/bigint, got ${typeof value}`);
2511
+ }
2512
+ break;
2513
+ default:
2514
+ break;
2515
+ }
2516
+ }
2517
+ };
2518
+ var globalRegistry = null;
2519
+ function getGlobalRegistry() {
2520
+ if (!globalRegistry) {
2521
+ globalRegistry = new CircuitRegistry();
2522
+ }
2523
+ return globalRegistry;
2524
+ }
2525
+ function defineCircuit(metadata, jsCircuit) {
2526
+ const registry = getGlobalRegistry();
2527
+ return registry.register({ ...metadata, jsCircuit });
2528
+ }
2529
+
2530
+ // src/server/OffchainVerifier.ts
2531
+ var OffchainVerifier = class {
2532
+ circuits = /* @__PURE__ */ new Map();
2533
+ compiledCircuits = /* @__PURE__ */ new Map();
2534
+ config;
2535
+ constructor(config = {}) {
2536
+ this.config = config;
2537
+ }
2538
+ /**
2539
+ * Registers a circuit for verification.
2540
+ *
2541
+ * @param name - Unique name for the circuit
2542
+ * @param config - Circuit configuration
2543
+ */
2544
+ async registerCircuit(name, config) {
2545
+ this.circuits.set(name, config);
2546
+ if (config.compiledCircuit) {
2547
+ this.compiledCircuits.set(name, config.compiledCircuit);
2548
+ return;
2549
+ }
2550
+ if (this.config.compiler) {
2551
+ const compiled = await this.config.compiler(config.jsCircuit);
2552
+ this.compiledCircuits.set(name, compiled);
2553
+ }
2554
+ }
2555
+ /**
2556
+ * Registers a pre-compiled circuit.
2557
+ *
2558
+ * @param name - Unique name for the circuit
2559
+ * @param compiled - Pre-compiled circuit
2560
+ */
2561
+ registerCompiledCircuit(name, compiled) {
2562
+ this.compiledCircuits.set(name, compiled);
2563
+ }
2564
+ /**
2565
+ * Verifies a ZK proof.
2566
+ *
2567
+ * @param request - Verification request with circuit name, proof, and public inputs
2568
+ * @returns Verification result
2569
+ */
2570
+ async verify(request) {
2571
+ const startTime = performance.now();
2572
+ const { circuitName, proof, publicInputs } = request;
2573
+ const compiled = this.compiledCircuits.get(circuitName);
2574
+ if (!compiled) {
2575
+ return {
2576
+ verified: false,
2577
+ circuitName,
2578
+ verificationTimeMs: performance.now() - startTime,
2579
+ error: `Circuit '${circuitName}' not registered`,
2580
+ publicInputs
2581
+ };
2582
+ }
2583
+ const config = this.circuits.get(circuitName);
2584
+ if (config?.publicInputCount !== void 0) {
2585
+ if (publicInputs.length !== config.publicInputCount) {
2586
+ return {
2587
+ verified: false,
2588
+ circuitName,
2589
+ verificationTimeMs: performance.now() - startTime,
2590
+ error: `Expected ${config.publicInputCount} public inputs, got ${publicInputs.length}`,
2591
+ publicInputs
2592
+ };
2593
+ }
2594
+ }
2595
+ try {
2596
+ const proofBytes = this.toUint8Array(proof);
2597
+ const publicInputBytes = publicInputs.map(
2598
+ (input) => this.publicInputToBytes(input)
2599
+ );
2600
+ if (!this.config.verifier) {
2601
+ return {
2602
+ verified: false,
2603
+ circuitName,
2604
+ verificationTimeMs: performance.now() - startTime,
2605
+ error: "No verifier configured. Provide a verifier in the config.",
2606
+ publicInputs
2607
+ };
2608
+ }
2609
+ const verified = await this.config.verifier(
2610
+ compiled,
2611
+ proofBytes,
2612
+ publicInputBytes
2613
+ );
2614
+ return {
2615
+ verified,
2616
+ circuitName,
2617
+ verificationTimeMs: performance.now() - startTime,
2618
+ publicInputs
2619
+ };
2620
+ } catch (error) {
2621
+ return {
2622
+ verified: false,
2623
+ circuitName,
2624
+ verificationTimeMs: performance.now() - startTime,
2625
+ error: error instanceof Error ? error.message : "Unknown verification error",
2626
+ publicInputs
2627
+ };
2628
+ }
2629
+ }
2630
+ /**
2631
+ * Checks if a circuit is registered.
2632
+ *
2633
+ * @param name - Circuit name
2634
+ */
2635
+ hasCircuit(name) {
2636
+ return this.compiledCircuits.has(name);
2637
+ }
2638
+ /**
2639
+ * Gets all registered circuit names.
2640
+ */
2641
+ getCircuitNames() {
2642
+ return Array.from(this.compiledCircuits.keys());
2643
+ }
2644
+ /**
2645
+ * Removes a circuit from the verifier.
2646
+ *
2647
+ * @param name - Circuit name to remove
2648
+ */
2649
+ removeCircuit(name) {
2650
+ this.circuits.delete(name);
2651
+ return this.compiledCircuits.delete(name);
2652
+ }
2653
+ // Private helpers
2654
+ toUint8Array(input) {
2655
+ if (input instanceof Uint8Array) {
2656
+ return input;
2657
+ }
2658
+ const hex = input.startsWith("0x") ? input.slice(2) : input;
2659
+ const bytes = new Uint8Array(hex.length / 2);
2660
+ for (let i = 0; i < bytes.length; i++) {
2661
+ bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
2662
+ }
2663
+ return bytes;
2664
+ }
2665
+ publicInputToBytes(input) {
2666
+ let value;
2667
+ if (typeof input === "string") {
2668
+ value = input.startsWith("0x") ? BigInt(input) : BigInt(input);
2669
+ } else if (typeof input === "bigint") {
2670
+ value = input;
2671
+ } else {
2672
+ value = BigInt(input);
2673
+ }
2674
+ const bytes = new Uint8Array(32);
2675
+ for (let i = 31; i >= 0; i--) {
2676
+ bytes[i] = Number(value & 0xffn);
2677
+ value >>= 8n;
2678
+ }
2679
+ return bytes;
2680
+ }
2681
+ };
2682
+ function createVerifierMiddleware(verifier) {
2683
+ return async (req, res, next) => {
2684
+ try {
2685
+ const { circuitName, proof, publicInputs } = req.body;
2686
+ if (!circuitName || typeof circuitName !== "string") {
2687
+ res.status(400).json({
2688
+ error: "Missing or invalid circuitName"
2689
+ });
2690
+ return;
2691
+ }
2692
+ if (!proof) {
2693
+ res.status(400).json({
2694
+ error: "Missing proof"
2695
+ });
2696
+ return;
2697
+ }
2698
+ if (!Array.isArray(publicInputs)) {
2699
+ res.status(400).json({
2700
+ error: "Missing or invalid publicInputs (expected array)"
2701
+ });
2702
+ return;
2703
+ }
2704
+ if (!verifier.hasCircuit(circuitName)) {
2705
+ res.status(404).json({
2706
+ error: `Circuit '${circuitName}' not found`
2707
+ });
2708
+ return;
2709
+ }
2710
+ const result = await verifier.verify({
2711
+ circuitName,
2712
+ proof,
2713
+ publicInputs
2714
+ });
2715
+ if (result.verified) {
2716
+ res.status(200).json(result);
2717
+ } else {
2718
+ res.status(400).json(result);
2719
+ }
2720
+ } catch (error) {
2721
+ next(error instanceof Error ? error : new Error(String(error)));
2722
+ }
2723
+ };
2724
+ }
2725
+ function createVerificationEndpoint(verifier, options = {}) {
2726
+ const baseMiddleware = createVerifierMiddleware(verifier);
2727
+ const wrappedMiddleware = async (req, res, next) => {
2728
+ if (options.allowedCircuits && options.allowedCircuits.length > 0 && req.body.circuitName) {
2729
+ if (!options.allowedCircuits.includes(req.body.circuitName)) {
2730
+ res.status(403).json({
2731
+ error: `Circuit '${req.body.circuitName}' not allowed`
2732
+ });
2733
+ return;
2734
+ }
2735
+ }
2736
+ await baseMiddleware(req, res, next);
2737
+ };
2738
+ return {
2739
+ path: options.path ?? "/verify",
2740
+ middleware: wrappedMiddleware
2741
+ };
2742
+ }
2743
+ async function batchVerify(verifier, requests) {
2744
+ const startTime = performance.now();
2745
+ const results = await Promise.all(
2746
+ requests.map((request) => verifier.verify(request))
2747
+ );
2748
+ const verifiedCount = results.filter((r) => r.verified).length;
2749
+ return {
2750
+ results,
2751
+ totalTimeMs: performance.now() - startTime,
2752
+ verifiedCount,
2753
+ failedCount: results.length - verifiedCount
2754
+ };
2755
+ }
2756
+ // Annotate the CommonJS export names for ESM import in node:
2757
+ 0 && (module.exports = {
2758
+ AcornParser,
2759
+ ArkworksWasm,
2760
+ Barretenberg,
2761
+ Chain,
2762
+ CircuitRegistry,
2763
+ CreateProofUseCase,
2764
+ IZI_NOIR_PROGRAM_ID,
2765
+ IziNoir,
2766
+ NETWORK_ENDPOINTS,
2767
+ OffchainVerifier,
2768
+ Provider,
2769
+ SolanaFormatter,
2770
+ SolanaTransactionBuilder,
2771
+ VkDeploymentManager,
2772
+ batchVerify,
2773
+ buildInitVkFromBytesData,
2774
+ buildVerifyProofData,
2775
+ calculateVkAccountRent,
2776
+ calculateVkAccountSize,
2777
+ createArkworksWasmContainer,
2778
+ createDefaultContainer,
2779
+ createNodeVkDeploymentManager,
2780
+ createVerificationEndpoint,
2781
+ createVerifierMiddleware,
2782
+ defineCircuit,
2783
+ generateNoir,
2784
+ getGlobalRegistry,
2785
+ initNoirWasm,
2786
+ isArkworksCircuit,
2787
+ isWasmInitialized,
2788
+ markWasmInitialized,
2789
+ parseProof,
2790
+ parsePublicInputs,
2791
+ parseVerifyingKey
2792
+ });
2793
+ //# sourceMappingURL=index.cjs.map