From 109ee87f2dc5f0eb69d9286188bf986df2dc6e18 Mon Sep 17 00:00:00 2001 From: nol4lej Date: Wed, 8 Apr 2026 12:09:15 -0400 Subject: [PATCH 1/3] =?UTF-8?q?feat(proof-generator):=20v3.5.0=20=E2=80=94?= =?UTF-8?q?=20clean=20architecture,=20dual=20backend,=20pnpm,=20Vitest?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Complete source refactor: src/{generate,disclosure,errors,providers,utils,wasm}/ - Add arkworks backend via @orbinum/groth16-proofs WASM (snarkjs remains default) - Bump @orbinum/groth16-proofs 2.1.0 → 3.0.0 (ProofError, num_public_signals fix) - Bump @orbinum/circuits ^0.4.1 → 0.4.4 - Migrate Jest → Vitest, npm/package-lock → pnpm - Add scripts/benchmark.ts with phase breakdown (Load/Witness/Serialize/Prove) - Update docs: api.md, development.md, README with real benchmark numbers - No breaking changes to public API --- .husky/pre-commit | 1 - CHANGELOG.md | 51 + README.md | 36 +- docs/api.md | 250 +- docs/backends.md | 123 + docs/development.md | 556 +- docs/usage.md | 237 + jest.config.js | 40 - lint-staged.config.js | 6 - package-lock.json | 5929 -------------------- package.json | 41 +- pnpm-lock.yaml | 1825 ++++++ scripts/benchmark.ts | 452 ++ src/circuits.ts | 130 - src/circuits/config.ts | 31 + src/circuits/index.ts | 2 + src/circuits/types.ts | 37 + src/{disclosure.ts => disclosure/index.ts} | 17 +- src/disclosure/types.ts | 36 + src/errors/index.ts | 35 + src/generate/backends/arkworks.ts | 60 + src/generate/backends/snarkjs.ts | 64 + src/generate/index.ts | 49 + src/generate/provider.ts | 13 + src/generate/types.ts | 8 + src/index.ts | 171 +- src/provider.ts | 17 - src/providers/index.ts | 4 + src/providers/interface.ts | 12 + src/providers/node.ts | 66 + src/providers/web.ts | 205 + src/types.ts | 123 - src/utils.ts | 185 - src/utils/encoding.ts | 54 + src/utils/formatting.ts | 41 + src/utils/index.ts | 13 + src/utils/validation.ts | 29 + src/wasm-loader.ts | 91 - src/wasm/index.ts | 1 + src/wasm/loader.ts | 146 + src/wasm/types.ts | 5 + tests/circuits/config.test.ts | 73 + tests/disclosure/index.test.ts | 199 + tests/errors/index.test.ts | 84 + tests/generate/index.test.ts | 237 + tests/generate/provider.test.ts | 46 + tests/integration/disclosure.test.ts | 131 - tests/integration/transfer.test.ts | 257 - tests/integration/unshield.test.ts | 146 - tests/providers/node.test.ts | 157 + tests/providers/web.test.ts | 351 ++ tests/unit/circuits.test.ts | 83 - tests/unit/disclosure.test.ts | 571 -- tests/unit/index.test.ts | 119 - tests/unit/provider.test.ts | 72 - tests/unit/utils.test.ts | 143 - tests/utils/encoding.test.ts | 128 + tests/utils/formatting.test.ts | 112 + tests/utils/validation.test.ts | 90 + tests/wasm/loader.test.ts | 157 + tsconfig.json | 23 +- tsconfig.test.json | 6 +- vitest.config.ts | 15 + 63 files changed, 5805 insertions(+), 8587 deletions(-) delete mode 100755 .husky/pre-commit create mode 100644 docs/backends.md create mode 100644 docs/usage.md delete mode 100644 jest.config.js delete mode 100644 lint-staged.config.js delete mode 100644 package-lock.json create mode 100644 pnpm-lock.yaml create mode 100644 scripts/benchmark.ts delete mode 100644 src/circuits.ts create mode 100644 src/circuits/config.ts create mode 100644 src/circuits/index.ts create mode 100644 src/circuits/types.ts rename src/{disclosure.ts => disclosure/index.ts} (91%) create mode 100644 src/disclosure/types.ts create mode 100644 src/errors/index.ts create mode 100644 src/generate/backends/arkworks.ts create mode 100644 src/generate/backends/snarkjs.ts create mode 100644 src/generate/index.ts create mode 100644 src/generate/provider.ts create mode 100644 src/generate/types.ts delete mode 100644 src/provider.ts create mode 100644 src/providers/index.ts create mode 100644 src/providers/interface.ts create mode 100644 src/providers/node.ts create mode 100644 src/providers/web.ts delete mode 100644 src/types.ts delete mode 100644 src/utils.ts create mode 100644 src/utils/encoding.ts create mode 100644 src/utils/formatting.ts create mode 100644 src/utils/index.ts create mode 100644 src/utils/validation.ts delete mode 100644 src/wasm-loader.ts create mode 100644 src/wasm/index.ts create mode 100644 src/wasm/loader.ts create mode 100644 src/wasm/types.ts create mode 100644 tests/circuits/config.test.ts create mode 100644 tests/disclosure/index.test.ts create mode 100644 tests/errors/index.test.ts create mode 100644 tests/generate/index.test.ts create mode 100644 tests/generate/provider.test.ts delete mode 100644 tests/integration/disclosure.test.ts delete mode 100644 tests/integration/transfer.test.ts delete mode 100644 tests/integration/unshield.test.ts create mode 100644 tests/providers/node.test.ts create mode 100644 tests/providers/web.test.ts delete mode 100644 tests/unit/circuits.test.ts delete mode 100644 tests/unit/disclosure.test.ts delete mode 100644 tests/unit/index.test.ts delete mode 100644 tests/unit/provider.test.ts delete mode 100644 tests/unit/utils.test.ts create mode 100644 tests/utils/encoding.test.ts create mode 100644 tests/utils/formatting.test.ts create mode 100644 tests/utils/validation.test.ts create mode 100644 tests/wasm/loader.test.ts create mode 100644 vitest.config.ts diff --git a/.husky/pre-commit b/.husky/pre-commit deleted file mode 100755 index 2312dc5..0000000 --- a/.husky/pre-commit +++ /dev/null @@ -1 +0,0 @@ -npx lint-staged diff --git a/CHANGELOG.md b/CHANGELOG.md index da2db10..a73a57e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,57 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [3.5.0] - 2026-04-08 + +### Added + +- **`src/circuits/types.ts`** — circuit types extracted to their own module: `CircuitType`, `CircuitInputValue`, `CircuitInputs`, `ProofResult`, `CircuitConfig`. +- **`src/wasm/`** — universal WASM loader (`initWasm`, `compressSnarkjsProofWasm`, `generateProofFromWitnessWasm`) supporting Node.js (reads `.wasm` from disk) and browser (fetches from CDN). +- **`src/wasm/types.ts`** — `WitnessData` type. +- **`src/errors/index.ts`** — error hierarchy: `ProofGeneratorError`, `WitnessCalculationError`, `ProofGenerationError`, `CircuitNotFoundError`, `InvalidInputsError`. +- **`src/disclosure/types.ts`** — `DisclosureMask`, `DisclosureProofOutput`. +- **`src/generate/types.ts`** — `GenerateOptions` interface (public). +- **`src/generate/provider.ts`** — `resolveProvider()` (auto-detects Node.js vs browser/web worker). +- **`src/generate/backends/snarkjs.ts`** — `runSnarkjsBackend()`. +- **`src/generate/backends/arkworks.ts`** — `runArkworksBackend()` using `@orbinum/groth16-proofs` WASM. +- **`src/providers/`** — `NodeArtifactProvider`, `WebArtifactProvider` (accepts `WebProviderOptions`), `ArtifactProvider` interface. +- **`src/utils/`** — `encoding.ts`, `formatting.ts`, `validation.ts`. +- **`scripts/benchmark.ts`** — full benchmark with `PhaseResult` / `benchPhased()` and PHASE BREAKDOWN output (Load / Witness / Serialize / Prove / Compress per circuit per backend). +- **New docs**: `docs/backends.md`, `docs/usage.md`. +- **New tests**: `tests/generate/`, `tests/disclosure/`, `tests/errors/`, `tests/circuits/`, `tests/providers/`, `tests/utils/`, `tests/wasm/` — full coverage for all new modules. + +### Changed + +- **`@orbinum/groth16-proofs`** bumped `2.1.0` → `3.0.0`. + - `generate_proof_from_witness` now requires explicit `num_public_signals` — bug fix for heuristic that produced wrong public signal counts. + - Return type changed from `String` to typed `ProofError` enum. + - New exports: `from_decimal_str`, `from_hex_le`, `prove_from_witness`, `compress_snarkjs_proof`. + - Benchmark verified: no performance regression. +- **`@orbinum/circuits`** bumped `^0.4.1` → `0.4.4`. +- **`src/generate.ts`** (flat file) refactored into `src/generate/` with orchestrator, provider resolution, and two isolated backends. +- **`src/disclosure.ts`** converted to `src/disclosure/` directory. +- **`src/errors.ts`** converted to `src/errors/` directory. +- **`src/index.ts`** reorganised into explicit sections: Core API, Types, Circuits, Providers, Utils, WASM. +- Migrated from **Jest** to **Vitest** (`vitest.config.ts`). +- Migrated from **npm** / `package-lock.json` to **pnpm**. +- **`docs/api.md`** updated: `generateProof` signature reflects `GenerateOptions`; full error hierarchy; performance tables with per-circuit / per-backend times. +- **`docs/development.md`** updated: directory tree, pnpm, Vitest, architecture diagram, key source files. +- **`README.md`** updated: real benchmark numbers and phase breakdown table. + +### Removed + +- **`src/types.ts`** — types distributed to their respective modules. +- **`src/generate.ts`**, **`src/disclosure.ts`**, **`src/errors.ts`**, **`src/provider.ts`**, **`src/utils.ts`**, **`src/circuits.ts`**, **`src/wasm-loader.ts`** — replaced by directory-based modules. +- **`jest.config.js`**, **`lint-staged.config.js`**, **`package-lock.json`**, **`.husky/pre-commit`** — replaced by Vitest + pnpm. +- **`CircuitConfig.provingKeyPath`** — `.ark` path no longer exposed in the public interface. +- Tests under `tests/unit/` and `tests/integration/` — reorganised into module-based directories. + + + +- **`CircuitConfig.provingKeyPath`** removed from the interface in `src/types.ts` — the `.ark` file path is no longer exposed. +- Monolithic source files replaced: `src/circuits.ts`, `src/provider.ts`, `src/utils.ts`, `src/wasm-loader.ts`. +- **Husky pre-commit hook** and **lint-staged** removed. + ## [3.3.2] - 2026-03-08 ### Changed diff --git a/README.md b/README.md index 81871ea..1e8940e 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![License](https://img.shields.io/badge/License-Apache%202.0%20%7C%20GPL%203.0-blue.svg)](LICENSE) [![Node.js](https://img.shields.io/badge/node-%3E%3D22.0.0-brightgreen.svg)](https://nodejs.org/) -Generate **128-byte Groth16 ZK-SNARK proofs** in ~6-8.5 seconds. Same TypeScript code runs identically in Node.js, browsers, Electron, and Tauri. +Generate **128-byte Groth16 ZK-SNARK proofs** in ~400ms (small circuits, post-warmup). Same TypeScript code runs identically in Node.js, browsers, Electron, and Tauri. **New in v2.0**: Circuit artifacts and WASM modules are now installed automatically as npm dependencies (`@orbinum/circuits` and `@orbinum/groth16-proofs`). No more manual downloads! @@ -43,13 +43,45 @@ console.log('Signals:', result.publicSignals); // ['0x...', ...] ## Features -- ✅ **Fast**: ~8.5s end-to-end (500ms witness + 5-8s proof) +- ✅ **Fast**: ~80ms per proof (small circuits, snarkjs backend); ~253ms with arkworks backend - ✅ **Optimized**: Direct decimal format pipeline (no conversion overhead) - ✅ **Compact**: 128-byte proofs (50% smaller than snarkjs) - ✅ **Universal**: Node.js, browsers, Electron, Tauri - same code - ✅ **Simple**: No build tools, no Rust, no setup - ✅ **Type-Safe**: Full TypeScript types +## Performance + +Benchmarked on Apple M-series (Node.js, 3 runs post-warmup): + +| Circuit | snarkjs backend | arkworks backend | First call overhead | +|---------|----------------|-----------------|---------------------| +| Disclosure | ~80ms | ~253ms | +1.5–2s (WASM init) | +| PrivateLink | ~73ms | ~234ms | +1.5–2s (WASM init) | +| Unshield | ~407ms | ~2.1s | +1.5–2s (WASM init) | +| Transfer | ~1.2s | ~7.2s | +1.5–2s (WASM init) | + +> **snarkjs backend** (default): uses snarkjs `fullProve` with `.zkey` proving keys — fastest option post-warmup. +> +> **arkworks backend**: uses snarkjs witness-only + arkworks WASM with `.ark` proving keys — ~3× slower for small circuits (Disclosure, PrivateLink), ~5× slower for large circuits (Unshield, Transfer). `.ark` artifacts are 2–3× smaller than `.zkey`. + +The first proof call in a process incurs the WASM initialization overhead (~1.5–2s). All subsequent proofs skip this. + +**Phase breakdown — where each backend spends its time (1 run):** + +| Circuit | Backend | Load | Witness | Serialize | Prove | Compress | Total | +|---------|---------|------|---------|-----------|-------|----------|-------| +| Disclosure | snarkjs | 9ms | — | — | 78ms | — | 87ms | +| Disclosure | arkworks | 2ms | 20ms | 3ms | 228ms | — | 253ms | +| PrivateLink | snarkjs | 8ms | — | — | 75ms | — | 83ms | +| PrivateLink | arkworks | 2ms | 14ms | 2ms | 216ms | — | 234ms | +| Unshield | snarkjs | 21ms | — | — | 367ms | — | 388ms | +| Unshield | arkworks | 8ms | 28ms | 26ms | 1965ms | — | 2027ms | +| Transfer | snarkjs | 54ms | — | — | 1212ms | — | 1266ms | +| Transfer | arkworks | 24ms | 94ms | 101ms | 6901ms | — | 7120ms | + +> `Prove` represents 97% of total time for large circuits (Unshield, Transfer). Load, witness calculation, and serialization are negligible. For arkworks, `Prove` includes PK deserialization + `Groth16::prove` inside WASM. + ## Supported Circuits | Circuit | Use Case | diff --git a/docs/api.md b/docs/api.md index 69b26bd..5cc307c 100644 --- a/docs/api.md +++ b/docs/api.md @@ -27,6 +27,7 @@ npm install @orbinum/proof-generator ```typescript import { generateProof, CircuitType } from '@orbinum/proof-generator'; +// Default backend (snarkjs) — fastest const result = await generateProof(CircuitType.Unshield, { merkle_root: '0x...', nullifier: '0x...', @@ -34,8 +35,14 @@ const result = await generateProof(CircuitType.Unshield, { // ... circuit-specific inputs }); -console.log('Proof:', result.proof); // 0x... (128 bytes) -console.log('Signals:', result.publicSignals); // ['0x...', ...] +// Arkworks backend — smaller artifacts +const result2 = await generateProof(CircuitType.Transfer, inputs, { + backend: 'arkworks', +}); + +console.log(result.proof); // '0xabcd...' (128-byte hex) +console.log(result.publicSignals); // ['0x...', ...] +console.log(result.circuitType); // CircuitType.Unshield ``` ## Core API @@ -49,21 +56,28 @@ Generates a **128-byte Groth16 proof** from circuit inputs. ```typescript await generateProof( circuitType: CircuitType, - inputs: Record, - options?: { - verbose?: boolean; // Log progress (default: false) - validateArtifacts?: boolean; // Verify files exist (default: true) - } + inputs: CircuitInputs, + options?: GenerateOptions ) ``` -**Returns:** +**`GenerateOptions`:** ```typescript -{ - proof: string; // 128-byte hex proof (0x...) - publicSignals: string[]; // Public signals (4-5 elements, hex encoded) - circuitType: string; // Circuit identifier (lowercase) +interface GenerateOptions { + verbose?: boolean; // Log progress to console (default: false) + provider?: ArtifactProvider; // Override artifact source (default: auto-detected) + backend?: 'snarkjs' | 'arkworks'; // Proof backend (default: 'snarkjs') +} +``` + +**Returns:** `Promise` + +```typescript +interface ProofResult { + proof: string; // 128-byte hex proof (0x-prefixed) + publicSignals: string[]; // Public signals (hex-encoded, 0x-prefixed) + circuitType: CircuitType; // Circuit used } ``` @@ -82,7 +96,7 @@ const result = await generateProof( path_elements: ['0x...', '0x...'], path_index: '0', }, - { verbose: true } + { verbose: true, backend: 'snarkjs' } ); console.log(result.proof); @@ -91,58 +105,68 @@ console.log(result.publicSignals); // ['0x...', '0x...', '0x...', '0x...', '0x...'] ``` -### `calculateWitness(inputs, wasmPath)` +--- -**Advanced use only.** Calculate witness array separately from proof generation. +### `generateDisclosureProof(value, ownerPubkey, blinding, assetId, commitment, mask, options?)` -Most users should use `generateProof()` instead, which handles witness calculation internally. +High-level helper for the `Disclosure` circuit. Handles Poseidon key derivation +(`viewing_key = Poseidon(ownerPubkey)`) and returns human-readable revealed data. **Parameters:** ```typescript -const witness = await calculateWitness( - inputs: Record, - wasmPath: string // Path to circuit WASM file +await generateDisclosureProof( + value: bigint, // Note value (u64) + ownerPubkey: bigint, // Owner public key (BN254 scalar) + blinding: bigint, // Blinding factor + assetId: bigint, // Asset ID (u32) + commitment: bigint, // Note commitment + mask: DisclosureMask, // Which fields to disclose + options?: GenerateOptions ) ``` -**Returns:** +**`DisclosureMask`:** ```typescript -string[] // Witness array (decimal strings) +interface DisclosureMask { + discloseValue: boolean; // Reveal note value + discloseAssetId: boolean; // Reveal asset ID + discloseOwner: boolean; // Reveal Poseidon(ownerPubkey) +} ``` -**Example:** +**Returns:** `Promise` ```typescript -import { calculateWitness } from '@orbinum/proof-generator'; -import { getCircuitConfig, CircuitType } from '@orbinum/proof-generator'; - -const config = getCircuitConfig(CircuitType.Unshield); -const witness = await calculateWitness( - { merkle_root: '0x...', nullifier: '0x...' /* ... */ }, - config.wasmPath -); +interface DisclosureProofOutput { + proof: string; // 128-byte compressed proof (0x-prefixed) + publicSignals: string[]; // [commitment, revealed_value, revealed_asset_id, revealed_owner_hash] + revealedData: { + value?: string; // Decimal string, or undefined if not disclosed + assetId?: number; // Number, or undefined if not disclosed + ownerHash?: string; // 0x-prefixed hex, or undefined if not disclosed + }; +} ``` -### `isReady()` - -Check if circuit artifacts are available for proof generation. - -**Returns:** `boolean` - `true` if artifacts exist, `false` otherwise - **Example:** ```typescript -import { isReady } from '@orbinum/proof-generator'; - -if (!isReady()) { - console.error('Circuit artifacts missing. Run: npm install'); - process.exit(1); -} +import { generateDisclosureProof } from '@orbinum/proof-generator'; + +const result = await generateDisclosureProof( + 1000n, // value + ownerPubkey, // bigint + blinding, // bigint + 42n, // assetId + commitment, // bigint + { discloseValue: true, discloseAssetId: true, discloseOwner: false } +); -// Safe to generate proofs -await generateProof(CircuitType.Unshield, inputs); +console.log(result.revealedData.value); // '1000' +console.log(result.revealedData.assetId); // 42 +console.log(result.revealedData.ownerHash); // undefined (not disclosed) ``` ## Enumerations @@ -171,58 +195,90 @@ await generateProof(CircuitType.Disclosure, inputs); await generateProof(CircuitType.PrivateLink, inputs); ``` -## Error Handling +## Providers + +### Auto-detection + +By default the library detects the runtime environment and picks the appropriate provider: -### Error Types +- **Node.js** → `NodeArtifactProvider` (reads from `node_modules/@orbinum/circuits` via `fs`) +- **Browser / Web Worker** (`window` or `self` defined) → `WebArtifactProvider` (fetches over HTTP) + +### `NodeArtifactProvider` ```typescript -import { - CircuitNotFoundError, - ProofGenerationError, - InvalidInputsError, -} from '@orbinum/proof-generator'; +import { NodeArtifactProvider } from '@orbinum/proof-generator'; + +const provider = new NodeArtifactProvider(); +// optional: pass a custom path to @orbinum/circuits package root +const custom = new NodeArtifactProvider('/path/to/circuits'); + +const result = await generateProof(CircuitType.Unshield, inputs, { provider }); ``` -### `InvalidInputsError` +### `WebArtifactProvider` -Thrown when circuit inputs are invalid (missing required fields, null values, wrong types). +Fetches artifacts over HTTP. Suitable for browsers, React Native, or any environment without a local filesystem. ```typescript -try { - await generateProof(CircuitType.Unshield, { - merkle_root: '0x...', // missing other required inputs - }); -} catch (error) { - if (error instanceof InvalidInputsError) { - console.error('Invalid inputs:', error.message); - } -} +import { WebArtifactProvider } from '@orbinum/proof-generator'; + +const provider = new WebArtifactProvider({ + baseUrl: 'https://cdn.example.com/circuits', + // optional per-circuit URL overrides: + // wasmUrls?: Partial> + // zkeyUrls?: Partial> + // provingKeyUrls?: Partial> +}); + +const result = await generateProof(CircuitType.Unshield, inputs, { provider }); ``` -### `CircuitNotFoundError` +### `ArtifactProvider` Interface -Thrown when circuit artifacts are missing (WASM file not found). +Implement this interface to supply artifacts from any source (IPFS, S3, embedded buffers, etc.): ```typescript -try { - await generateProof(CircuitType.Unshield, inputs); -} catch (error) { - if (error instanceof CircuitNotFoundError) { - console.error('Circuit artifacts missing. Run: npm install'); - } +interface ArtifactProvider { + getCircuitWasm(circuitType: CircuitType): Promise; + getCircuitZkey(circuitType: CircuitType): Promise; + getCircuitProvingKey?(circuitType: CircuitType): Promise; // required for arkworks backend } ``` -### `ProofGenerationError` +## Error Handling + +All errors extend `ProofGeneratorError`, which carries a machine-readable `code` string. + +```typescript +import { + ProofGeneratorError, + WitnessCalculationError, + ProofGenerationError, + CircuitNotFoundError, + InvalidInputsError, +} from '@orbinum/proof-generator'; +``` + +| Error class | `code` | Thrown when | +| --- | --- | --- | +| `InvalidInputsError` | `INVALID_INPUTS` | Missing or malformed circuit inputs | +| `CircuitNotFoundError` | `CIRCUIT_NOT_FOUND` | Circuit artifacts not found | +| `WitnessCalculationError` | `WITNESS_CALCULATION_FAILED` | snarkjs witness step fails | +| `ProofGenerationError` | `PROOF_GENERATION_FAILED` | Backend proof step fails | -Thrown during proof generation (witness calculation or WASM proof generation). +**Example:** ```typescript try { await generateProof(CircuitType.Unshield, inputs); } catch (error) { - if (error instanceof ProofGenerationError) { - console.error('Proof generation failed:', error.message); + if (error instanceof InvalidInputsError) { + console.error('Bad inputs:', error.message); // error.code === 'INVALID_INPUTS' + } else if (error instanceof CircuitNotFoundError) { + console.error('Missing artifacts. Run: pnpm install'); + } else if (error instanceof ProofGeneratorError) { + console.error(`Proof failed [${error.code}]:`, error.message); } } ``` @@ -253,21 +309,35 @@ All public signals returned as **0x-prefixed hex strings**: ## Performance -### Benchmarks +See [docs/backends.md](backends.md) for a full benchmark analysis. -| Operation | Time | -| ---------------------------- | ----------- | -| Witness generation (snarkjs) | ~500ms | -| Proof generation (WASM) | ~5-8s | -| **Total** | **~6-8.5s** | -| Module load (cold start) | ~1s | -| Module load (cached) | ~0ms | +### By backend + +| Circuit | snarkjs | arkworks | +| --- | --- | --- | +| Unshield | ~1.3 s | ~7 s | +| Transfer | ~4.7 s | ~20 s | +| Disclosure | ~1.1 s | ~5 s | +| PrivateLink | ~0.7 s | ~3 s | + +- **snarkjs** — default, fastest, uses `.zkey` proving keys +- **arkworks** — 2–3× smaller proof artifacts, uses `.ark` proving keys + +### WASM initialization + +The arkworks WASM module is initialized lazily on first use. Pre-initialize for latency-sensitive apps: + +```typescript +import { initWasm } from '@orbinum/proof-generator'; + +await initWasm(); // call once at startup +``` -### Memory Usage +### Memory -- Peak: ~2GB during proof generation -- WASM module size: ~5MB -- Circuits total: ~20-50MB resident +- Peak: ~2 GB during proof generation +- WASM module: ~5 MB +- Circuit artifacts: ~20–50 MB total ## Troubleshooting @@ -276,8 +346,8 @@ All public signals returned as **0x-prefixed hex strings**: Dependency not installed: ```bash -rm -rf node_modules package-lock.json -npm install +rm -rf node_modules pnpm-lock.yaml +pnpm install ``` ### "Out of memory" error @@ -364,4 +434,6 @@ For faster proofs, ensure: --- -**See [docs/development.md](development.md) for development setup and architecture details.** +**See [docs/backends.md](backends.md) for backend architecture and benchmark analysis.** +**See [docs/usage.md](usage.md) for usage examples with both backends.** +**See [docs/development.md](development.md) for development setup and contributing guide.** diff --git a/docs/backends.md b/docs/backends.md new file mode 100644 index 0000000..28e6fe8 --- /dev/null +++ b/docs/backends.md @@ -0,0 +1,123 @@ +# Backend Comparison: snarkjs vs arkworks + +`@orbinum/proof-generator` supports two proof generation backends that can be selected per call. This document explains how each backend works, when to use each one, and what the performance numbers look like. + +## Overview + +| | snarkjs | arkworks | +|---|---|---| +| **Proving key format** | `.zkey` | `.ark` | +| **Proof generation** | JavaScript (snarkjs `groth16.fullProve`) | WASM (arkworks `Groth16::prove`) | +| **Artifact size** | Larger (`.zkey`) | 2–3× smaller (`.ark`) | +| **Speed (small circuits)** | ~80ms | ~250–280ms | +| **Speed (large circuits)** | ~380ms–1.3s | ~2s–7s | +| **Default** | ✅ Yes | No | + +--- + +## How Each Backend Works + +### snarkjs (default) + +``` +inputs → snarkjs.groth16.fullProve(inputs, wasm, zkey) + → { proof (G1/G2 points), publicSignals } + → compressSnarkjsProofWasm(proof) + → 128-byte compressed Groth16 proof +``` + +`fullProve` handles everything internally: it calculates the witness using the circuit WASM, then generates the proof using the `.zkey` proving key — all within the same snarkjs call. The raw snarkjs output is then compressed to the 128-byte arkworks canonical format via a small WASM helper. + +**Phase breakdown (1 run, Apple M-series):** + +| Circuit | Load | Prove (fullProve) | Compress | Total | +|---------|------|-------------------|----------|-------| +| Disclosure | 8ms | 84ms | 1ms | ~93ms | +| PrivateLink | 8ms | 70ms | — | ~78ms | +| Unshield | 21ms | 365ms | — | ~386ms | +| Transfer | 54ms | 1194ms | — | ~1248ms | + +### arkworks + +``` +inputs → snarkjs.wtns.calculate(inputs, wasm, buffer) + → snarkjs.wtns.exportJson(buffer) → bigint[] + → JSON.stringify(witness.map(v => v.toString())) + → generateProofFromWitnessWasm(numSignals, witnessJson, arkBytes) + → 128-byte compressed Groth16 proof +``` + +The arkworks backend splits the work in two: snarkjs calculates the witness in memory using the circuit WASM, then the pre-serialised witness is handed off to an arkworks WASM module that performs the actual Groth16 proof using a smaller `.ark` proving key. + +**Phase breakdown (1 run, Apple M-series):** + +| Circuit | Load | Witness | Serialize | Prove (WASM) | Total | +|---------|------|---------|-----------|--------------|-------| +| Disclosure | 1ms | 21ms | 3ms | 226ms | ~251ms | +| PrivateLink | 2ms | 14ms | 2ms | 214ms | ~232ms | +| Unshield | 8ms | 29ms | 27ms | 1955ms | ~2019ms | +| Transfer | 27ms | 78ms | 99ms | 7093ms | ~7297ms | + +> `Prove` represents 97% of total time for large circuits. Load, witness calculation, and serialization are negligible. + +--- + +## Benchmark Results + +Measured on Apple M-series, Node.js ≥ 22, 3 runs post-warmup (median reported): + +| Circuit | snarkjs | arkworks | Ratio | +|---------|---------|----------|-------| +| Disclosure | 80ms | 282ms | 0.28× | +| PrivateLink | 74ms | 232ms | 0.32× | +| Unshield | 380ms | 2061ms | 0.18× | +| Transfer | 1323ms | 7041ms | 0.19× | + +snarkjs is consistently **3–5× faster** than arkworks post-warmup. + +### First-call overhead + +Both backends incur a one-time WASM initialisation cost the first time they are used in a process: + +- **snarkjs**: minimal (JS module, no WASM init) +- **arkworks**: +1.5–2s (WASM binary loaded and compiled once, then cached) + +Subsequent calls within the same process skip this overhead entirely. + +--- + +## Key Differences + +### Proving key format + +- **`.zkey`** (snarkjs): larger files, self-contained, widely compatible. +- **`.ark`** (arkworks): 2–3× smaller because the key uses a compressed representation. Both formats provide identical security. + +### Where proof generation happens + +- **snarkjs**: pure JavaScript running in the Node.js / browser JS engine. +- **arkworks**: native Rust code compiled to WASM — fully sandboxed, same binary in Node.js and browser. + +### Why snarkjs is faster + +snarkjs `fullProve` is highly optimised for BN254 in JavaScript and has had years of performance tuning. The arkworks WASM module includes pk deserialization inside the proof call, which adds overhead particularly visible on large circuits like `Transfer`. + +### Why you might choose arkworks anyway + +- **Smaller artifacts**: `.ark` files reduce bandwidth and storage — relevant for browser or mobile deployments. +- **Consistency**: the same WASM binary runs identically in every environment with no JS engine differences. +- **Future**: as the arkworks WASM module matures, the performance gap is expected to narrow. + +--- + +## Choosing a Backend + +| Scenario | Recommended backend | +|---|---| +| Server-side Node.js, latency matters | `snarkjs` (default) | +| Browser / mobile, bandwidth matters | `arkworks` (smaller `.ark` keys) | +| Offline / air-gapped environments | Either (both work offline) | +| You need the fastest possible proof | `snarkjs` | +| Artifact storage is constrained | `arkworks` | + +In practice, default to `snarkjs`. Switch to `arkworks` only when artifact size or environment constraints make it the better trade-off. diff --git a/docs/development.md b/docs/development.md index cef3656..f187537 100644 --- a/docs/development.md +++ b/docs/development.md @@ -10,60 +10,101 @@ Development setup, architecture, and testing for `@orbinum/proof-generator`. # Clone and install git clone https://github.com/orbinum/proof-generator.git cd proof-generator -npm install +pnpm install -# Build TypeScript -npm run build +# Type-check (includes tests/) +pnpm typecheck # Run tests -npm test +pnpm test ``` ### Requirements - **Node.js**: ≥ 22.0.0 +- **pnpm**: ≥ 10.0.0 - **Git**: For version control -- **npm**: ≥ 9.0.0 ## Project Structure ``` proof-generator/ ├── src/ -│ ├── index.ts Main API export point -│ ├── wasm-loader.ts WASM module initialization (arkworks) -│ ├── witness.ts snarkjs integration (witness calculation) -│ ├── circuits.ts Circuit configuration and validation -│ ├── types.ts TypeScript type definitions -│ └── utils.ts Validation and formatting utilities +│ ├── index.ts Public API barrel (no logic) +│ │ +│ ├── generate/ Proof orchestration +│ │ ├── index.ts generateProof() entry point +│ │ ├── types.ts GenerateOptions interface +│ │ ├── provider.ts resolveProvider() — auto-detects environment +│ │ └── backends/ +│ │ ├── snarkjs.ts runSnarkjsBackend() +│ │ └── arkworks.ts runArkworksBackend() +│ │ +│ ├── disclosure/ Selective disclosure helpers +│ │ ├── index.ts generateDisclosureProof() +│ │ └── types.ts DisclosureMask, DisclosureProofOutput +│ │ +│ ├── circuits/ Circuit configuration +│ │ ├── config.ts getCircuitConfig() +│ │ ├── index.ts Re-exports +│ │ └── types.ts CircuitType, CircuitInputs, ProofResult, CircuitConfig +│ │ +│ ├── errors/ +│ │ └── index.ts Error class hierarchy +│ │ +│ ├── providers/ Artifact providers +│ │ ├── interface.ts ArtifactProvider interface +│ │ ├── node.ts NodeArtifactProvider +│ │ ├── web.ts WebArtifactProvider +│ │ └── index.ts Re-exports +│ │ +│ ├── wasm/ WASM module management +│ │ ├── index.ts initWasm, compressSnarkjsProofWasm, generateProofFromWitnessWasm +│ │ ├── loader.ts Lazy-load groth16-proofs WASM +│ │ └── types.ts WitnessData +│ │ +│ └── utils/ +│ ├── encoding.ts bigIntToBytes32, hexSignalToBigInt, … +│ ├── formatting.ts normalizeProofHex, formatPublicSignalsArray, … +│ ├── validation.ts validateInputs, validatePublicSignals, validateProofSize +│ └── index.ts Re-exports │ -├── tests/ -│ ├── unit/ Unit tests (55 tests) -│ │ ├── circuits.test.ts Circuit configuration tests (13 tests) -│ │ ├── index.test.ts API exports and error types (18 tests) -│ │ └── utils.test.ts Utility functions tests (24 tests) -│ └── integration/ Integration tests (9 tests) -│ ├── unshield.test.ts Unshield proof generation (4 tests) -│ ├── transfer.test.ts Transfer proof generation (4 tests) -│ └── disclosure.test.ts Disclosure proof generation (4 tests) +├── tests/ Mirrors src/ structure +│ ├── generate/ +│ │ ├── index.test.ts generateProof() — 15 tests +│ │ └── provider.test.ts resolveProvider() — 4 tests +│ ├── disclosure/ +│ │ └── index.test.ts generateDisclosureProof() — 9 tests +│ ├── errors/ +│ │ └── index.test.ts Error class hierarchy — 11 tests +│ ├── circuits/ +│ │ └── config.test.ts Circuit config resolution +│ ├── providers/ +│ │ ├── node.test.ts NodeArtifactProvider +│ │ └── web.test.ts WebArtifactProvider +│ ├── utils/ +│ │ ├── encoding.test.ts +│ │ ├── formatting.test.ts +│ │ └── validation.test.ts +│ ├── wasm/ +│ │ └── loader.test.ts +│ └── generate.test.ts Integration: real proof generation (all 4 circuits) │ -├── docs/ -│ ├── api.md Complete API reference -│ └── development.md This file -│ -├── .github/ -│ └── workflows/ GitHub Actions CI/CD +├── scripts/ +│ ├── benchmark.ts Full proof benchmark (all circuits × backends) +│ └── test-ark-backend.ts arkworks backend smoke test │ -├── .husky/ Pre-commit hook configuration -├── dist/ Compiled JavaScript (build output) -├── node_modules/ -│ ├── @orbinum/circuits/ Circuit artifacts (npm package) -│ └── @orbinum/groth16-proofs/ Proof generation WASM (npm package) +├── docs/ +│ ├── api.md Complete API reference +│ ├── backends.md Backend comparison + benchmarks +│ ├── development.md This file +│ └── usage.md Usage guide │ -├── jest.config.js Jest test configuration -├── tsconfig.json TypeScript configuration -├── package.json Dependencies and scripts -└── README.md Project overview +├── tsconfig.json Production TypeScript config +├── tsconfig.test.json Test TypeScript config (includes tests/) +├── vitest.config.ts Vitest configuration +├── package.json Dependencies and scripts +└── README.md Project overview ``` ## Development Workflow @@ -71,205 +112,187 @@ proof-generator/ ### Build ```bash -npm run build +pnpm build ``` -Compiles TypeScript to JavaScript: +Compiles TypeScript to `dist/`: - Source: `src/**/*.ts` - Output: `dist/**/*.js` -- Target: ES2020, CommonJS modules +- Target: ES2022, CommonJS modules ### Testing ```bash # Run all tests -npm test +pnpm test # Watch mode (rerun on changes) -npm run test:watch - -# Single test file -npm test -- unshield.test.ts +pnpm test:watch # With coverage -npm test -- --coverage +pnpm test:coverage -# Verbose output -npm test -- --verbose +# Single file +pnpm test tests/generate/index.test.ts ``` -**Test Setup:** +**Test setup:** -- Framework: Jest 29.7.0 -- TypeScript: ts-jest 29.2.5 -- Uses real WASM modules -- Uses real proving keys from groth16-proofs -- No mocks - integration tests only +- Framework: **Vitest 4.1.3** +- TypeScript: native support (no ts-jest) +- External modules (`snarkjs`, `@orbinum/groth16-proofs`, `circomlibjs`) are mocked in unit tests +- `tests/generate.test.ts` runs real proof generation (integration) ### Code Formatting ```bash # Format all TypeScript -npm run format +pnpm format # Check formatting (no changes) -npm run format:check - -# Type checking -npm run lint +pnpm format:check -# Combined check (before commit) -npm run format && npm run lint +# Type checking (includes tests/) +pnpm typecheck ``` **Tools:** -- Formatter: Prettier 3.4.2 -- Linter: TypeScript compiler (tsc) +- Formatter: Prettier 3.8.1 +- Type checker: TypeScript compiler (tsc) -### Clean Rebuild +### Full pre-publish check ```bash -npm run clean # Remove build artifacts and node_modules -npm install # Reinstall everything -npm run build # Rebuild +pnpm check ``` -## Pre-commit Hooks +Runs: lint → typecheck → format:check → build → tests. -Uses **Husky 9.1.7** + **lint-staged 15.2.11**: +### Clean Rebuild -Automatically runs on `git commit`: +```bash +pnpm clean # Remove dist, node_modules, lockfile +pnpm install # Reinstall everything +pnpm build # Rebuild +``` -1. Format TypeScript files -2. Validate types with tsc -3. Ensure no syntax errors +## Key Source Files -**Configuration:** `.husky/pre-commit` +### `src/generate/index.ts` -**Skip hooks (if needed):** +Orchestrator for all proof generation. Validates inputs, resolves provider, dispatches to backend. -```bash -git commit --no-verify +```typescript +export async function generateProof( + circuitType: CircuitType, + inputs: CircuitInputs, + options: GenerateOptions = {} +): Promise ``` -## Key Source Files +Flow: +1. `validateInputs(inputs)` — throws `InvalidInputsError` on bad inputs +2. `resolveProvider(options.provider)` — auto-detect or use override +3. `getCircuitConfig(circuitType)` — resolve artifact paths +4. `runSnarkjsBackend(...)` or `runArkworksBackend(...)` depending on `options.backend` +5. `validatePublicSignals(...)` — throws `ProofGenerationError` on invalid output -### `src/wasm-loader.ts` +### `src/generate/provider.ts` -Manages WASM module initialization (lazy loading). +Auto-detects runtime environment and returns the default provider. ```typescript -export async function initWasm(): Promise { - // Idempotent: Only initializes once - // Dynamically imports WASM module from @orbinum/groth16-proofs - // Works identically in Node.js and browsers +export function resolveProvider(override?: ArtifactProvider): ArtifactProvider { + if (override) return override; + if (typeof window !== 'undefined' || typeof self !== 'undefined') + return new WebArtifactProvider(...); + return new NodeArtifactProvider(); } +``` -export async function compressSnarkjsProofWasm(proof: SnarkjsProofLike): Promise { - // Compress snarkjs proof to arkworks 128-byte format -} +### `src/generate/backends/snarkjs.ts` + +``` +provider.getCircuitWasm + getCircuitZkey + → snarkjs.groth16.fullProve(inputs, wasm, zkey) + → compressSnarkjsProofWasm(proof) // 128-byte compression + → validateProofSize ``` -**Key Design:** +### `src/generate/backends/arkworks.ts` -- Lazy initialization (on first use) -- Universal environment support (Node.js, Browser, Electron, Tauri) -- Dynamic imports with environment-specific initialization -- Auto-initialization on first proof compression call +``` +provider.getCircuitWasm + getCircuitProvingKey (.ark) + → snarkjs.wtns.calculate(inputs, wasm) + → snarkjs.wtns.exportJson(wtns) + → generateProofFromWitnessWasm(witness, provingKey) +``` -### `src/witness.ts` +### `src/disclosure/index.ts` -snarkjs integration for witness calculation. +Uses `circomlibjs.buildPoseidon` to compute `viewing_key = Poseidon(ownerPubkey)`, then calls +`generateProof(CircuitType.Disclosure, ...)` and maps raw signals to `DisclosureProofOutput.revealedData`. -```typescript -export async function calculateWitness( - inputs: Record, - wasmPath: string -): Promise { - // Uses snarkjs wtns functions - // Returns witness array (11,808 elements) -} +### `src/errors/index.ts` + +Error hierarchy: + +``` +ProofGeneratorError (base, has .code) +├── WitnessCalculationError (code: 'WITNESS_CALCULATION_FAILED') +├── ProofGenerationError (code: 'PROOF_GENERATION_FAILED') +├── CircuitNotFoundError (code: 'CIRCUIT_NOT_FOUND') +└── InvalidInputsError (code: 'INVALID_INPUTS') ``` -### `src/index.ts` +### `src/wasm/index.ts` -Main public API. +Manages lifecycle of the `@orbinum/groth16-proofs` WASM module. Lazy-initializes on first use; idempotent. ```typescript -export async function generateProof( - circuitType: CircuitType, - inputs: CircuitInputs, - options?: GenerateProofOptions -): Promise; - -export { calculateWitness } from './witness'; -export { isReady } from './utils'; -export { CircuitType } from './types'; -export * from './types'; // All type exports +export async function initWasm(): Promise +export async function compressSnarkjsProofWasm(proof): Promise +export async function generateProofFromWitnessWasm(witness, provingKey): Promise<{ proof, publicSignals }> ``` ## Architecture Overview -### Proof Generation Flow +### Two-Backend Design ``` -User Input (JSON) - ↓ -[1] Validate inputs - ↓ -[2] Load circuit WASM (witness calculator) - ↓ -[3] snarkjs: Calculate witness (decimal format) - ↓ [OPTIMIZED: No conversion needed!] - ↓ -[4] Load proving key (arkworks format .ark) +User Input ↓ -[5] Load groth16-proofs WASM (proof generation) - ↓ -[6] groth16-proofs: Convert decimal → field elements - ↓ -[7] arkworks: Generate 128-byte proof - ↓ -Output (proof + publicSignals) +generateProof() + ↓ [validateInputs] + ↓ [resolveProvider] + ↓ [getCircuitConfig] + ├── backend: 'snarkjs' (default) ──────────────────────────────────▮ + │ getCircuitWasm + getCircuitZkey │ + │ → snarkjs.groth16.fullProve │ + │ → compressSnarkjsProofWasm (128-byte) │ + │ │ + └── backend: 'arkworks' ────────────────────────────────────────▮ + getCircuitWasm + getCircuitProvingKey (.ark) │ + → snarkjs.wtns.calculate → snarkjs.wtns.exportJson │ + → generateProofFromWitnessWasm (arkworks WASM) │ + ↓ + ProofResult { proof, publicSignals, circuitType } ``` ### Module Integration -- **snarkjs 0.7.5**: Witness calculation from Circom circuits - - Consumes: circuit WASM, inputs - - Produces: witness array (decimal strings - native format) -- **groth16-proofs**: Groth16 proof generation (compiled WASM) - - Consumes: witness (decimal), proving key - - Internally converts: decimal → field elements (LE) - - Produces: 128-byte proof + public signals -- **TypeScript wrapper**: Orchestrates the pipeline - - Handles paths, validation, error handling - - No witness format conversion needed ✅ - - Same code everywhere +- **snarkjs 0.7.6**: Witness calculation for all circuits; also the full prover in the `snarkjs` backend +- **@orbinum/groth16-proofs 2.1.0**: Arkworks Groth16 WASM — proof generation in `arkworks` backend, and 128-byte compression for `snarkjs` backend +- **circomlibjs 0.1.7**: Poseidon hash implementation — used exclusively in `src/disclosure/` -### Data Types +### Provider System -**Circuit Inputs:** - -```typescript -Record; -``` - -**Witness (Updated):** - -```typescript -string[] // 11,808 elements (decimal strings: "1", "12345", etc.) ``` - -**Proof Output:** - -```typescript -{ - proof: string, // '0x...' (256 hex chars) - publicSignals: string[], // 4-5 elements, hex encoded -} +ArtifactProvider (interface) +├── NodeArtifactProvider — reads from node_modules/@orbinum/circuits via fs +└── WebArtifactProvider — fetches over HTTP (configurable base URL) ``` ## Artifact Management @@ -278,23 +301,23 @@ string[] // 11,808 elements (decimal strings: "1", "12345", etc.) **Circuit artifacts are managed via npm packages:** -1. **@orbinum/circuits** (v0.3.0+) +1. **@orbinum/circuits** (0.4.4) - Circuit WASM files (witness calculators) - - Proving keys (.ark format for arkworks) - - Verification keys (.zkey format for snarkjs) + - Proving keys (`.ark` for arkworks backend) + - Verification keys (`.zkey` for snarkjs backend) - Installed automatically as dependency -2. **@orbinum/groth16-proofs** (v2.0.0+) - - Precompiled WASM module (arkworks Groth16) - - Proof generation and compression +2. **@orbinum/groth16-proofs** (2.1.0) + - Precompiled Arkworks Groth16 WASM + - Proof generation and 128-byte compression - Installed automatically as dependency -**No manual downloads or postinstall scripts required!** +**No manual downloads or postinstall scripts required.** ### Artifact Locations -After `npm install`, artifacts are in `node_modules/`: +After `pnpm install`, artifacts are in `node_modules/`: ``` node_modules/ @@ -307,7 +330,10 @@ node_modules/ │ ├── transfer_pk.zkey │ ├── disclosure.wasm │ ├── disclosure_pk.ark -│ └── disclosure_pk.zkey +│ ├── disclosure_pk.zkey +│ ├── private_link.wasm +│ ├── private_link_pk.ark +│ └── private_link_pk.zkey └── @orbinum/groth16-proofs/ ├── groth16_proofs_bg.wasm ├── groth16_proofs.js @@ -316,131 +342,122 @@ node_modules/ ### Version Management -Update versions in `package.json`: - -```json -{ - "dependencies": { - "@orbinum/circuits": "^0.3.0", - "@orbinum/groth16-proofs": "^2.0.0" - } -} -``` - -Then: +Update versions in `package.json`, then: ```bash -npm update -npm install +pnpm update +pnpm install ``` ## Testing Strategy -### Test Organization +**Framework:** Vitest 4.1.3 +**Total:** 144 tests across 11 suites -**Two-tier test structure:** +### Test Organization -1. **Unit Tests** (`tests/unit/`): Fast, isolated component testing +``` +tests/ +├── generate/ +│ ├── index.test.ts (15 tests) generateProof — mocked provider & backends +│ └── provider.test.ts ( 4 tests) resolveProvider — environment detection +├── disclosure/ +│ └── index.test.ts ( 9 tests) generateDisclosureProof — mocked Poseidon +├── errors/ +│ └── index.test.ts (11 tests) Error hierarchy and .code values +├── circuits/ +│ └── config.test.ts Circuit config resolution +├── providers/ +│ ├── node.test.ts NodeArtifactProvider +│ └── web.test.ts WebArtifactProvider +├── utils/ +│ ├── encoding.test.ts +│ ├── formatting.test.ts +│ └── validation.test.ts +├── wasm/ +│ └── loader.test.ts +└── generate.test.ts Integration: real proof generation (all 4 circuits) +``` - - `circuits.test.ts` (13 tests): Circuit configuration resolution - - `index.test.ts` (18 tests): API exports, error types, isReady() - - `utils.test.ts` (24 tests): Validation and formatting utilities +### Mocking Approach -2. **Integration Tests** (`tests/integration/`): End-to-end proof generation - - `unshield.test.ts` (4 tests): Complete unshield proof flow - - `transfer.test.ts` (4 tests): Complete transfer proof flow - - `disclosure.test.ts` (4 tests): Complete disclosure proof flow +External dependencies are mocked with `vi.mock`: -**Total: 64 tests (55 unit + 9 integration)** +- `snarkjs` — `groth16.fullProve`, `wtns.calculate`, `wtns.exportJson` +- `@orbinum/groth16-proofs` — `generate_proof_from_witness`, `compress_snarkjs_proof` +- `circomlibjs` — `buildPoseidon` returns `Object.assign(vi.fn(), { F: { toObject: vi.fn() } })` -### Test Structure +Providers return `Uint8Array` stubs in unit tests — no real artifacts required. -**Unit Test Example:** +### Unit Test Example ```typescript -describe('circuits.ts - Unit Tests', () => { - test('should resolve circuit config from package', () => { - const config = getCircuitConfig(CircuitType.Unshield); - expect(config.wasmPath).toContain('unshield.wasm'); - expect(config.zkeyPath).toContain('unshield_pk.zkey'); +describe('generateProof', () => { + it('should dispatch to snarkjs backend by default', async () => { + await generateProof(CircuitType.Unshield, validInputs); + expect(runSnarkjsBackend).toHaveBeenCalledOnce(); + expect(runArkworksBackend).not.toHaveBeenCalled(); }); }); ``` -**Integration Test Example:** +### Integration Test Example ```typescript -describe('Integration: Unshield Proof Generation', () => { - test('should generate valid proof for unshield', async () => { +describe('Integration: real proofs', () => { + it('should generate valid unshield proof', async () => { const result = await generateProof(CircuitType.Unshield, inputs); - expect(result.proof).toBeDefined(); - expect(result.proof.length).toBe(258); // 0x + 256 hex chars - expect(result.publicSignals.length).toBe(5); + expect(result.proof).toMatch(/^0x[0-9a-f]{256}$/); + expect(result.publicSignals).toHaveLength(5); }); }); ``` -### Test Coverage - -**Unit Tests:** - -- ✅ Circuit artifact path resolution -- ✅ Configuration validation -- ✅ Public API exports -- ✅ Error class instantiation -- ✅ Utility function behavior -- ✅ Input validation and formatting - -**Integration Tests:** - -- ✅ Valid proof generation for all 3 circuits -- ✅ Invalid input handling -- ✅ Missing required fields detection -- ✅ Null/undefined input rejection -- ✅ Real WASM module integration -- ✅ Real circuit artifacts usage - -**Run tests:** +### Run Tests ```bash -# All tests -npm test - -# Unit tests only -npm test -- tests/unit - -# Integration tests only -npm test -- tests/integration - -# Specific test file -npm test -- tests/unit/circuits.test.ts +pnpm test # All 144 tests +pnpm test tests/generate/ # Only generate suite +pnpm test tests/generate/index.test.ts # Single file +pnpm test:coverage # With coverage report ``` ## Dependencies ### Runtime -- **snarkjs**: 0.7.5 (witness calculation) -- **arkworks**: Compiled as groth16-proofs WASM +| Package | Version | Purpose | +| --- | --- | --- | +| `@orbinum/circuits` | `0.4.4` | Circuit WASM + proving keys | +| `@orbinum/groth16-proofs` | `2.1.0` | Arkworks WASM proof generation | +| `snarkjs` | `0.7.6` | Witness calculation + snarkjs proving | ### Development -- **TypeScript**: 5.7.3 -- **Jest**: 29.7.0 (testing) -- **Prettier**: 3.4.2 (formatting) -- **Husky**: 9.1.7 (Git hooks) -- **lint-staged**: 15.2.11 (pre-commit filtering) +| Package | Version | Purpose | +| --- | --- | --- | +| `vitest` | `4.1.3` | Test runner | +| `@vitest/coverage-v8` | `4.1.3` | Coverage reports | +| `typescript` | `6.0.2` | Compiler | +| `prettier` | `3.8.1` | Code formatting | +| `circomlibjs` | `0.1.7` | Poseidon hash (disclosure module) | +| `@types/node` | `25.5.2` | Node.js type definitions | +| `@types/snarkjs` | `0.7.9` | snarkjs type definitions | +| `@types/circomlibjs` | `0.1.6` | circomlibjs type definitions | -**See:** `package.json` for complete dependency list. +**See:** `package.json` for the complete list. ## Compilation Targets TypeScript configured for: -- **Target:** ES2020 +- **Target:** ES2022 - **Module:** CommonJS -- **Lib:** ES2020, DOM (for browser WASM) +- **moduleResolution:** node - **Strict:** true +- **types:** ["node"] + +`tsconfig.test.json` extends the base config and adds `tests/**` to `include`. See `tsconfig.json` for full configuration. @@ -462,36 +479,43 @@ Automatically publishes to npm. ## Common Development Tasks -### Add new circuit support +### Add a new circuit -1. Add circuit type to `src/types.ts` (CircuitType enum) -2. Update `getExpectedPublicSignals()` in `src/circuits.ts` -3. Add unit tests in `tests/unit/` -4. Add integration test in `tests/integration/{circuit}.test.ts` -5. Ensure @orbinum/circuits package includes new circuit artifacts -6. Update documentation in `docs/api.md` +1. Add the circuit type to `src/circuits/types.ts` (`CircuitType` enum) +2. Add its config entry in `src/circuits/config.ts` (`getCircuitConfig` switch) +3. Ensure `@orbinum/circuits` package includes the new artifact files +4. Add unit tests in `tests/circuits/config.test.ts` +5. Add integration test in `tests/generate.test.ts` +6. Update `docs/api.md` (Supported Circuits table) ### Update dependencies ```bash -npm update -npm run format -npm test +pnpm update +pnpm format +pnpm test ``` -### Release new version +### Release a new version ```bash npm version patch # or minor, major git push --tags -# GitHub Actions automatically publishes +# GitHub Actions automatically publishes to npm +``` + +### Run benchmarks + +```bash +npx tsx scripts/benchmark.ts ``` -### Debug failing test +Runs all 4 circuits × 2 backends and prints timing per phase. + +### Debug a failing test ```bash -npm test -- --verbose unshield.test.ts -NODE_DEBUG=* npm test -- unshield.test.ts +pnpm test -- --reporter=verbose tests/generate/index.test.ts ``` ## Resources @@ -499,7 +523,9 @@ NODE_DEBUG=* npm test -- unshield.test.ts - **Circom Documentation**: [docs.circom.io](https://docs.circom.io) - **snarkjs**: [github.com/iden3/snarkjs](https://github.com/iden3/snarkjs) - **arkworks**: [github.com/arkworks-rs/ark-groth16](https://github.com/arkworks-rs/ark-groth16) -- **Orbinum Node**: [github.com/orbinum/node](https://github.com/orbinum/node) +- **Backend comparison**: [docs/backends.md](backends.md) +- **Usage guide**: [docs/usage.md](usage.md) +- **API reference**: [docs/api.md](api.md) --- diff --git a/docs/usage.md b/docs/usage.md new file mode 100644 index 0000000..544c6fb --- /dev/null +++ b/docs/usage.md @@ -0,0 +1,237 @@ +# Usage Guide + +Practical guide to generating ZK-SNARK proofs with `@orbinum/proof-generator`. + +## Installation + +```bash +npm install @orbinum/proof-generator +``` + +Dependencies are installed automatically: +- `@orbinum/circuits` — circuit artifacts (WASM, proving keys) +- `@orbinum/groth16-proofs` — arkworks WASM proof generator + +--- + +## Basic Usage + +### Generating a proof (snarkjs backend — default) + +```typescript +import { generateProof, CircuitType } from '@orbinum/proof-generator'; + +const result = await generateProof(CircuitType.Unshield, { + merkle_root: '12345678...', + nullifier: '98765432...', + amount: '1000000000000000000', + secret: '11223344...', + path_elements: ['0x...', '0x...'], + path_index: '0', +}); + +console.log(result.proof); // "0xabcd..." (128 bytes, hex) +console.log(result.publicSignals); // ["0x...", "0x...", ...] (hex, LE-encoded) +console.log(result.circuitType); // "unshield" +``` + +All inputs must be decimal strings or numbers. Public signals are returned as 0x-prefixed 32-byte little-endian hex strings, ready for on-chain submission. + +### Switching to the arkworks backend + +Pass `backend: 'arkworks'` in the options object. Everything else stays the same: + +```typescript +const result = await generateProof( + CircuitType.Unshield, + { + merkle_root: '12345678...', + // ... same inputs as above + }, + { backend: 'arkworks' } +); +``` + +The arkworks backend uses `.ark` proving keys instead of `.zkey`. Both backends produce identical 128-byte Groth16 proofs — the output format is the same. + +See [backends.md](./backends.md) for a full comparison of speed and artifact size. + +--- + +## Supported Circuits + +| Circuit | `CircuitType` | Public signals | Use case | +|---------|--------------|----------------|----------| +| Unshield | `CircuitType.Unshield` | 5 | Withdraw from pool to public address | +| Transfer | `CircuitType.Transfer` | 5 | Private-to-private transfer | +| Disclosure | `CircuitType.Disclosure` | 4 | Selective field revelation to auditor | +| PrivateLink | `CircuitType.PrivateLink` | 2 | Privacy-preserving cross-chain identity | + +--- + +## Selective Disclosure + +The `Disclosure` circuit has a dedicated helper that handles Poseidon key derivation and decodes the public signals into human-readable output: + +```typescript +import { generateDisclosureProof } from '@orbinum/proof-generator'; +import type { DisclosureMask } from '@orbinum/proof-generator'; + +const mask: DisclosureMask = { + discloseValue: true, // reveal the note value + discloseAssetId: true, // reveal the asset ID + discloseOwner: false, // keep owner private +}; + +const result = await generateDisclosureProof( + 1000n, // value (bigint, u64) + pubkey, // ownerPubkey (bigint, BN254 scalar) + blinding, // blinding factor (bigint) + 1n, // assetId (bigint, u32) + commitment, // note commitment (bigint) + mask, +); + +console.log(result.proof); // "0x..." (128 bytes) +console.log(result.publicSignals); // 4 hex signals +console.log(result.revealedData); +// { +// commitment: "0x...", +// value: "1000", // decimal string (present because discloseValue: true) +// assetId: 1, // number (present because discloseAssetId: true) +// ownerHash: undefined // absent because discloseOwner: false +// } +``` + +At least one mask field must be `true` — passing all `false` throws an error. + +You can also use `generateProof(CircuitType.Disclosure, inputs)` directly if you build the circuit inputs object manually. + +--- + +## Provider Options + +By default, the library auto-detects the environment: +- **Node.js**: reads artifacts from `node_modules/@orbinum/circuits` on disk. +- **Browser / Web Worker**: fetches artifacts from the npm CDN (unpkg). + +### Custom artifact directory (Node.js) + +```typescript +import { generateProof, NodeArtifactProvider, CircuitType } from '@orbinum/proof-generator'; + +const provider = new NodeArtifactProvider('/path/to/my/artifacts'); + +const result = await generateProof(CircuitType.Transfer, inputs, { provider }); +``` + +### Self-hosted artifacts (browser) + +```typescript +import { generateProof, WebArtifactProvider, CircuitType } from '@orbinum/proof-generator'; + +const provider = new WebArtifactProvider({ + baseUrl: 'https://my-cdn.example.com/circuits', +}); + +const result = await generateProof(CircuitType.Transfer, inputs, { provider }); +``` + +The `WebArtifactProvider` in manifest mode (default, no options) fetches a `manifest.json` from the CDN to resolve exact versioned artifact filenames. You can pin specific circuits to a version: + +```typescript +const provider = new WebArtifactProvider({ + circuitVersions: { unshield: 1 }, // force v1 unshield artifacts +}); +``` + +--- + +## Error Handling + +```typescript +import { + generateProof, + CircuitType, + CircuitNotFoundError, + ProofGenerationError, + InvalidInputsError, +} from '@orbinum/proof-generator'; + +try { + const result = await generateProof(CircuitType.Unshield, inputs); +} catch (error) { + if (error instanceof InvalidInputsError) { + // A required input field is null, undefined, or missing + console.error('Bad inputs:', error.message); + } else if (error instanceof CircuitNotFoundError) { + // Artifact files could not be loaded (wrong path, network error, etc.) + console.error('Artifacts unavailable:', error.message); + } else if (error instanceof ProofGenerationError) { + // The proof failed to generate (invalid witness, corrupt key, etc.) + console.error('Proof failed:', error.message); + } else { + throw error; + } +} +``` + +All error classes extend `ProofGeneratorError`, which exposes a `code` string alongside the message: + +| Class | `code` | +|---|---| +| `WitnessCalculationError` | `WITNESS_CALCULATION_FAILED` | +| `ProofGenerationError` | `PROOF_GENERATION_FAILED` | +| `CircuitNotFoundError` | `CIRCUIT_NOT_FOUND` | +| `InvalidInputsError` | `INVALID_INPUTS` | + +--- + +## Verbose Logging + +Pass `verbose: true` to log each step to the console — useful for debugging or understanding where time is spent: + +```typescript +const result = await generateProof(CircuitType.Unshield, inputs, { verbose: true }); +// [proof-generator] Generating proof for circuit: unshield (backend: snarkjs) +// [proof-generator] Fetching circuit artifacts... +// [proof-generator] Step 1: Generating witness + proof with snarkjs... +// [proof-generator] Proof generated: 0xabcd1234...ef56 (truncated) +// [proof-generator] Public signals: 5 +// [proof-generator] Proof generation completed successfully. +``` + +--- + +## WASM Initialisation + +The first proof call in a process incurs a one-time WASM initialisation cost (~1.5–2s for the arkworks backend). You can pre-warm it explicitly to avoid latency on the first user-facing proof: + +```typescript +import { initWasm } from '@orbinum/proof-generator'; + +// Call at app startup, before the first proof request +await initWasm(); +``` + +`initWasm` is idempotent — safe to call multiple times. + +--- + +## Complete Options Reference + +```typescript +await generateProof( + circuitType: CircuitType, + inputs: Record, + options?: { + backend?: 'snarkjs' | 'arkworks'; // default: 'snarkjs' + provider?: ArtifactProvider; // default: auto-detected + verbose?: boolean; // default: false + } +): Promise<{ + proof: string; // 0x-prefixed 128-byte hex + publicSignals: string[]; // 0x-prefixed 32-byte LE hex per signal + circuitType: CircuitType; +}> +``` diff --git a/jest.config.js b/jest.config.js deleted file mode 100644 index 0c7911c..0000000 --- a/jest.config.js +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Jest configuration for @orbinum/proof-generator tests - */ - -module.exports = { - preset: 'ts-jest', - testEnvironment: 'node', - roots: ['/tests'], - testMatch: ['**/*.test.ts'], - collectCoverageFrom: [ - 'src/**/*.ts', - '!src/**/*.d.ts', - ], - coverageDirectory: 'coverage', - verbose: true, - testTimeout: 30000, // 30 seconds (proof generation can be slow) - - // Support ES modules from wasm-pack - extensionsToTreatAsEsm: ['.ts'], - moduleNameMapper: { - '^(\\.{1,2}/.*)\\.js$': '$1', - }, - transform: { - '^.+\\.tsx?$': [ - 'ts-jest', - { - useESM: true, - tsconfig: { - target: 'ES2020', - module: 'esnext', - }, - }, - ], - }, - // Don't transform WASM packages - use them as-is - transformIgnorePatterns: [ - 'node_modules/(?!@orbinum/groth16-proofs)', - ], -}; - diff --git a/lint-staged.config.js b/lint-staged.config.js deleted file mode 100644 index d03163d..0000000 --- a/lint-staged.config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - '*.ts': ['prettier --write'], - '*.{json,md}': ['prettier --write'], - // Run full project lint after all formatters complete - '*': () => 'npm run lint' -}; diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index cbe966b..0000000 --- a/package-lock.json +++ /dev/null @@ -1,5929 +0,0 @@ -{ - "name": "@orbinum/proof-generator", - "version": "3.3.2", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@orbinum/proof-generator", - "version": "3.3.2", - "license": "GPL-3.0-or-later OR Apache-2.0", - "dependencies": { - "@orbinum/circuits": "^0.4.2", - "@orbinum/groth16-proofs": "^2.0.0", - "snarkjs": "0.7.5" - }, - "devDependencies": { - "@types/circomlibjs": "0.1.6", - "@types/jest": "29.5.14", - "@types/node": "22.10.5", - "@types/snarkjs": "0.7.9", - "circomlibjs": "0.1.7", - "husky": "9.1.7", - "jest": "29.7.0", - "lint-staged": "15.2.11", - "prettier": "3.4.2", - "ts-jest": "29.2.5", - "typescript": "^5.7.3" - }, - "engines": { - "node": ">=22.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", - "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", - "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.29.0", - "@babel/types": "^7.29.0", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.29.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", - "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", - "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", - "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", - "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", - "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", - "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.28.6", - "@babel/types": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.0" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", - "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", - "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", - "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", - "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", - "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@ethersproject/abi": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.8.0.tgz", - "integrity": "sha512-b9YS/43ObplgyV6SlyQsG53/vkSal0MNA1fskSC4mbnCMi8R+NkcH8K9FPYNESf6jUefBUniE4SOKms0E/KK1Q==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/address": "^5.8.0", - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/constants": "^5.8.0", - "@ethersproject/hash": "^5.8.0", - "@ethersproject/keccak256": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/strings": "^5.8.0" - } - }, - "node_modules/@ethersproject/abstract-provider": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.8.0.tgz", - "integrity": "sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/networks": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/transactions": "^5.8.0", - "@ethersproject/web": "^5.8.0" - } - }, - "node_modules/@ethersproject/abstract-signer": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.8.0.tgz", - "integrity": "sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/abstract-provider": "^5.8.0", - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0" - } - }, - "node_modules/@ethersproject/address": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.8.0.tgz", - "integrity": "sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/keccak256": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/rlp": "^5.8.0" - } - }, - "node_modules/@ethersproject/base64": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.8.0.tgz", - "integrity": "sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bytes": "^5.8.0" - } - }, - "node_modules/@ethersproject/basex": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.8.0.tgz", - "integrity": "sha512-PIgTszMlDRmNwW9nhS6iqtVfdTAKosA7llYXNmGPw4YAI1PUyMv28988wAb41/gHF/WqGdoLv0erHaRcHRKW2Q==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/properties": "^5.8.0" - } - }, - "node_modules/@ethersproject/bignumber": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.8.0.tgz", - "integrity": "sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "bn.js": "^5.2.1" - } - }, - "node_modules/@ethersproject/bytes": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", - "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/logger": "^5.8.0" - } - }, - "node_modules/@ethersproject/constants": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.8.0.tgz", - "integrity": "sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bignumber": "^5.8.0" - } - }, - "node_modules/@ethersproject/contracts": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.8.0.tgz", - "integrity": "sha512-0eFjGz9GtuAi6MZwhb4uvUM216F38xiuR0yYCjKJpNfSEy4HUM8hvqqBj9Jmm0IUz8l0xKEhWwLIhPgxNY0yvQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/abi": "^5.8.0", - "@ethersproject/abstract-provider": "^5.8.0", - "@ethersproject/abstract-signer": "^5.8.0", - "@ethersproject/address": "^5.8.0", - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/constants": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/transactions": "^5.8.0" - } - }, - "node_modules/@ethersproject/hash": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.8.0.tgz", - "integrity": "sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/abstract-signer": "^5.8.0", - "@ethersproject/address": "^5.8.0", - "@ethersproject/base64": "^5.8.0", - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/keccak256": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/strings": "^5.8.0" - } - }, - "node_modules/@ethersproject/hdnode": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.8.0.tgz", - "integrity": "sha512-4bK1VF6E83/3/Im0ERnnUeWOY3P1BZml4ZD3wcH8Ys0/d1h1xaFt6Zc+Dh9zXf9TapGro0T4wvO71UTCp3/uoA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/abstract-signer": "^5.8.0", - "@ethersproject/basex": "^5.8.0", - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/pbkdf2": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/sha2": "^5.8.0", - "@ethersproject/signing-key": "^5.8.0", - "@ethersproject/strings": "^5.8.0", - "@ethersproject/transactions": "^5.8.0", - "@ethersproject/wordlists": "^5.8.0" - } - }, - "node_modules/@ethersproject/json-wallets": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.8.0.tgz", - "integrity": "sha512-HxblNck8FVUtNxS3VTEYJAcwiKYsBIF77W15HufqlBF9gGfhmYOJtYZp8fSDZtn9y5EaXTE87zDwzxRoTFk11w==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/abstract-signer": "^5.8.0", - "@ethersproject/address": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/hdnode": "^5.8.0", - "@ethersproject/keccak256": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/pbkdf2": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/random": "^5.8.0", - "@ethersproject/strings": "^5.8.0", - "@ethersproject/transactions": "^5.8.0", - "aes-js": "3.0.0", - "scrypt-js": "3.0.1" - } - }, - "node_modules/@ethersproject/keccak256": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.8.0.tgz", - "integrity": "sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "js-sha3": "0.8.0" - } - }, - "node_modules/@ethersproject/logger": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.8.0.tgz", - "integrity": "sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT" - }, - "node_modules/@ethersproject/networks": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.8.0.tgz", - "integrity": "sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/logger": "^5.8.0" - } - }, - "node_modules/@ethersproject/pbkdf2": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.8.0.tgz", - "integrity": "sha512-wuHiv97BrzCmfEaPbUFpMjlVg/IDkZThp9Ri88BpjRleg4iePJaj2SW8AIyE8cXn5V1tuAaMj6lzvsGJkGWskg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/sha2": "^5.8.0" - } - }, - "node_modules/@ethersproject/properties": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.8.0.tgz", - "integrity": "sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/logger": "^5.8.0" - } - }, - "node_modules/@ethersproject/providers": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.8.0.tgz", - "integrity": "sha512-3Il3oTzEx3o6kzcg9ZzbE+oCZYyY+3Zh83sKkn4s1DZfTUjIegHnN2Cm0kbn9YFy45FDVcuCLLONhU7ny0SsCw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/abstract-provider": "^5.8.0", - "@ethersproject/abstract-signer": "^5.8.0", - "@ethersproject/address": "^5.8.0", - "@ethersproject/base64": "^5.8.0", - "@ethersproject/basex": "^5.8.0", - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/constants": "^5.8.0", - "@ethersproject/hash": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/networks": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/random": "^5.8.0", - "@ethersproject/rlp": "^5.8.0", - "@ethersproject/sha2": "^5.8.0", - "@ethersproject/strings": "^5.8.0", - "@ethersproject/transactions": "^5.8.0", - "@ethersproject/web": "^5.8.0", - "bech32": "1.1.4", - "ws": "8.18.0" - } - }, - "node_modules/@ethersproject/random": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.8.0.tgz", - "integrity": "sha512-E4I5TDl7SVqyg4/kkA/qTfuLWAQGXmSOgYyO01So8hLfwgKvYK5snIlzxJMk72IFdG/7oh8yuSqY2KX7MMwg+A==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0" - } - }, - "node_modules/@ethersproject/rlp": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.8.0.tgz", - "integrity": "sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0" - } - }, - "node_modules/@ethersproject/sha2": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.8.0.tgz", - "integrity": "sha512-dDOUrXr9wF/YFltgTBYS0tKslPEKr6AekjqDW2dbn1L1xmjGR+9GiKu4ajxovnrDbwxAKdHjW8jNcwfz8PAz4A==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "hash.js": "1.1.7" - } - }, - "node_modules/@ethersproject/signing-key": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.8.0.tgz", - "integrity": "sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "bn.js": "^5.2.1", - "elliptic": "6.6.1", - "hash.js": "1.1.7" - } - }, - "node_modules/@ethersproject/solidity": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.8.0.tgz", - "integrity": "sha512-4CxFeCgmIWamOHwYN9d+QWGxye9qQLilpgTU0XhYs1OahkclF+ewO+3V1U0mvpiuQxm5EHHmv8f7ClVII8EHsA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/keccak256": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/sha2": "^5.8.0", - "@ethersproject/strings": "^5.8.0" - } - }, - "node_modules/@ethersproject/strings": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.8.0.tgz", - "integrity": "sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/constants": "^5.8.0", - "@ethersproject/logger": "^5.8.0" - } - }, - "node_modules/@ethersproject/transactions": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.8.0.tgz", - "integrity": "sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/address": "^5.8.0", - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/constants": "^5.8.0", - "@ethersproject/keccak256": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/rlp": "^5.8.0", - "@ethersproject/signing-key": "^5.8.0" - } - }, - "node_modules/@ethersproject/units": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.8.0.tgz", - "integrity": "sha512-lxq0CAnc5kMGIiWW4Mr041VT8IhNM+Pn5T3haO74XZWFulk7wH1Gv64HqE96hT4a7iiNMdOCFEBgaxWuk8ETKQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/constants": "^5.8.0", - "@ethersproject/logger": "^5.8.0" - } - }, - "node_modules/@ethersproject/wallet": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.8.0.tgz", - "integrity": "sha512-G+jnzmgg6UxurVKRKvw27h0kvG75YKXZKdlLYmAHeF32TGUzHkOFd7Zn6QHOTYRFWnfjtSSFjBowKo7vfrXzPA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/abstract-provider": "^5.8.0", - "@ethersproject/abstract-signer": "^5.8.0", - "@ethersproject/address": "^5.8.0", - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/hash": "^5.8.0", - "@ethersproject/hdnode": "^5.8.0", - "@ethersproject/json-wallets": "^5.8.0", - "@ethersproject/keccak256": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/random": "^5.8.0", - "@ethersproject/signing-key": "^5.8.0", - "@ethersproject/transactions": "^5.8.0", - "@ethersproject/wordlists": "^5.8.0" - } - }, - "node_modules/@ethersproject/web": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.8.0.tgz", - "integrity": "sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/base64": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/strings": "^5.8.0" - } - }, - "node_modules/@ethersproject/wordlists": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.8.0.tgz", - "integrity": "sha512-2df9bbXicZws2Sb5S6ET493uJ0Z84Fjr3pC4tu/qlnZERibZCeUVuqdtt+7Tv9xxhUxHoIekIA7avrKUWHrezg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/hash": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/strings": "^5.8.0" - } - }, - "node_modules/@iden3/bigarray": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/@iden3/bigarray/-/bigarray-0.0.2.tgz", - "integrity": "sha512-Xzdyxqm1bOFF6pdIsiHLLl3HkSLjbhqJHVyqaTxXt3RqXBEnmsUmEW47H7VOi/ak7TdkRpNkxjyK5Zbkm+y52g==", - "license": "GPL-3.0" - }, - "node_modules/@iden3/binfileutils": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/@iden3/binfileutils/-/binfileutils-0.0.12.tgz", - "integrity": "sha512-naAmzuDufRIcoNfQ1d99d7hGHufLA3wZSibtr4dMe6ZeiOPV1KwOZWTJ1YVz4HbaWlpDuzVU72dS4ATQS4PXBQ==", - "license": "GPL-3.0", - "dependencies": { - "fastfile": "0.0.20", - "ffjavascript": "^0.3.0" - } - }, - "node_modules/@iden3/binfileutils/node_modules/ffjavascript": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.3.1.tgz", - "integrity": "sha512-4PbK1WYodQtuF47D4pRI5KUg3Q392vuP5WjE1THSnceHdXwU3ijaoS0OqxTzLknCtz4Z2TtABzkBdBdMn3B/Aw==", - "license": "GPL-3.0", - "dependencies": { - "wasmbuilder": "0.0.16", - "wasmcurves": "0.2.2", - "web-worker": "1.2.0" - } - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", - "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/core": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", - "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/reporters": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.7.0", - "jest-config": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-resolve-dependencies": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "jest-watcher": "^29.7.0", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/environment": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", - "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "expect": "^29.7.0", - "jest-snapshot": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", - "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-get-type": "^29.6.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", - "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@sinonjs/fake-timers": "^10.0.2", - "@types/node": "*", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/globals": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", - "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/types": "^29.6.3", - "jest-mock": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", - "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^6.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/source-map": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", - "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.18", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", - "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", - "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/test-result": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", - "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@orbinum/circuits": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@orbinum/circuits/-/circuits-0.4.2.tgz", - "integrity": "sha512-26q2elFm4UVOMwZtmGDkK4E0ad1FSqgMBo0cJjLRQQp0qx7ca2HPFj0LM8lSMPHLfyuYEtKRof5xoIXQftS4XA==", - "license": "GPL-3.0", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@orbinum/groth16-proofs": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@orbinum/groth16-proofs/-/groth16-proofs-2.0.0.tgz", - "integrity": "sha512-DTgwoNLwgofd6OyHb45yCWcT5I6iQfqP3U7whvxgSWt6WUCtO4bvU39iCmOkY4LvjXCUVg6pBhMaSvC3MZkDDQ==", - "license": "Apache-2.0 OR GPL-3.0-or-later", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@sinclair/typebox": { - "version": "0.27.10", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz", - "integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", - "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sinonjs/commons": "^3.0.0" - } - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", - "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.2" - } - }, - "node_modules/@types/circomlibjs": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@types/circomlibjs/-/circomlibjs-0.1.6.tgz", - "integrity": "sha512-yF174bPDaiKgejlZzCSqKwZaqXhlxMcVEHrAtstFohwP05OjtvHXOdxO6HQeTg8WwIdgMg7MJb1WyWZdUCGlPQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", - "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", - "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", - "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/jest": { - "version": "29.5.14", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", - "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - } - }, - "node_modules/@types/node": { - "version": "22.10.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.5.tgz", - "integrity": "sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "node_modules/@types/snarkjs": { - "version": "0.7.9", - "resolved": "https://registry.npmjs.org/@types/snarkjs/-/snarkjs-0.7.9.tgz", - "integrity": "sha512-pb4Bq3GI2YQOQOG0dR/YuQs/mqcuL6k/vnz68LIPtpA2frrUL3twf69a3AUK9eUmNNeW0RIKkq6scDlC75Is+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/yargs": { - "version": "17.0.35", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", - "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/aes-js": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", - "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", - "dev": true, - "license": "MIT" - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/async": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", - "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", - "license": "MIT" - }, - "node_modules/b4a": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz", - "integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==", - "license": "Apache-2.0", - "peerDependencies": { - "react-native-b4a": "*" - }, - "peerDependenciesMeta": { - "react-native-b4a": { - "optional": true - } - } - }, - "node_modules/babel-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", - "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/transform": "^29.7.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.6.3", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", - "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", - "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-import-attributes": "^7.24.7", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5" - }, - "peerDependencies": { - "@babel/core": "^7.0.0 || ^8.0.0-0" - } - }, - "node_modules/babel-preset-jest": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", - "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", - "dev": true, - "license": "MIT", - "dependencies": { - "babel-plugin-jest-hoist": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" - }, - "node_modules/baseline-browser-mapping": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", - "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.cjs" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/bech32": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", - "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/bfj": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/bfj/-/bfj-7.1.0.tgz", - "integrity": "sha512-I6MMLkn+anzNdCUp9hMRyui1HaNEUCco50lxbvNS4+EyXg8lN3nJ48PjPWtbH8UVS9CuMoaKE9U2V3l29DaRQw==", - "license": "MIT", - "dependencies": { - "bluebird": "^3.7.2", - "check-types": "^11.2.3", - "hoopy": "^0.1.4", - "jsonpath": "^1.1.1", - "tryer": "^1.0.1" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/blake-hash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/blake-hash/-/blake-hash-2.0.0.tgz", - "integrity": "sha512-Igj8YowDu1PRkRsxZA7NVkdFNxH5rKv5cpLxQ0CVXSIA77pVYwCPRQJ2sMew/oneUpfuYRyjG6r8SmmmnbZb1w==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "node-addon-api": "^3.0.0", - "node-gyp-build": "^4.2.2", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/blake2b": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/blake2b/-/blake2b-2.1.4.tgz", - "integrity": "sha512-AyBuuJNI64gIvwx13qiICz6H6hpmjvYS5DGkG6jbXMOT8Z3WUJ3V1X0FlhIoT1b/5JtHE3ki+xjtMvu1nn+t9A==", - "dev": true, - "license": "ISC", - "dependencies": { - "blake2b-wasm": "^2.4.0", - "nanoassert": "^2.0.0" - } - }, - "node_modules/blake2b-wasm": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/blake2b-wasm/-/blake2b-wasm-2.4.0.tgz", - "integrity": "sha512-S1kwmW2ZhZFFFOghcx73+ZajEfKBqhP82JMssxtLVMxlaPea1p9uoLiUZ5WYyHn0KddwbLc+0vh4wR0KBNoT5w==", - "license": "MIT", - "dependencies": { - "b4a": "^1.0.1", - "nanoassert": "^2.0.0" - } - }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "license": "MIT" - }, - "node_modules/bn.js": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz", - "integrity": "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==", - "dev": true, - "license": "MIT" - }, - "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", - "dev": true, - "license": "MIT" - }, - "node_modules/browserslist": { - "version": "4.28.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", - "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "baseline-browser-mapping": "^2.9.0", - "caniuse-lite": "^1.0.30001759", - "electron-to-chromium": "^1.5.263", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.2.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-json-stable-stringify": "2.x" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001777", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001777.tgz", - "integrity": "sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/check-types": { - "version": "11.2.3", - "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.2.3.tgz", - "integrity": "sha512-+67P1GkJRaxQD6PKK0Et9DhwQB+vGg3PM5+aavopCpZT1lj9jeqfvpgTLAWErNj8qApkkmXlu/Ug74kmhagkXg==", - "license": "MIT" - }, - "node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/circom_runtime": { - "version": "0.1.28", - "resolved": "https://registry.npmjs.org/circom_runtime/-/circom_runtime-0.1.28.tgz", - "integrity": "sha512-ACagpQ7zBRLKDl5xRZ4KpmYIcZDUjOiNRuxvXLqhnnlLSVY1Dbvh73TI853nqoR0oEbihtWmMSjgc5f+pXf/jQ==", - "license": "Apache-2.0", - "dependencies": { - "ffjavascript": "0.3.1" - }, - "bin": { - "calcwit": "calcwit.js" - } - }, - "node_modules/circom_runtime/node_modules/ffjavascript": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.3.1.tgz", - "integrity": "sha512-4PbK1WYodQtuF47D4pRI5KUg3Q392vuP5WjE1THSnceHdXwU3ijaoS0OqxTzLknCtz4Z2TtABzkBdBdMn3B/Aw==", - "license": "GPL-3.0", - "dependencies": { - "wasmbuilder": "0.0.16", - "wasmcurves": "0.2.2", - "web-worker": "1.2.0" - } - }, - "node_modules/circomlibjs": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/circomlibjs/-/circomlibjs-0.1.7.tgz", - "integrity": "sha512-GRAUoAlKAsiiTa+PA725G9RmEmJJRc8tRFxw/zKktUxlQISGznT4hH4ESvW8FNTsrGg/nNd06sGP/Wlx0LUHVg==", - "dev": true, - "license": "GPL-3.0", - "dependencies": { - "blake-hash": "^2.0.0", - "blake2b": "^2.1.3", - "ethers": "^5.5.1", - "ffjavascript": "^0.2.45" - } - }, - "node_modules/cjs-module-lexer": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", - "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/cli-cursor": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", - "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "restore-cursor": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", - "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", - "dev": true, - "license": "MIT", - "dependencies": { - "slice-ansi": "^5.0.0", - "string-width": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/cliui/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/cliui/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", - "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", - "dev": true, - "license": "MIT" - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true, - "license": "MIT" - }, - "node_modules/commander": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", - "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/create-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", - "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "prompts": "^2.0.1" - }, - "bin": { - "create-jest": "bin/create-jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/dedent": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", - "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "babel-plugin-macros": "^3.1.0" - }, - "peerDependenciesMeta": { - "babel-plugin-macros": { - "optional": true - } - } - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/ejs": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", - "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", - "license": "Apache-2.0", - "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.5.307", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.307.tgz", - "integrity": "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==", - "dev": true, - "license": "ISC" - }, - "node_modules/elliptic": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", - "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", - "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", - "dev": true, - "license": "MIT" - }, - "node_modules/emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "dev": true, - "license": "MIT" - }, - "node_modules/environment": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", - "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/error-ex": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", - "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/escodegen": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", - "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", - "license": "BSD-2-Clause", - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ethers": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.8.0.tgz", - "integrity": "sha512-DUq+7fHrCg1aPDFCHx6UIPb3nmt2XMpM7Y/g2gLhsl3lIBqeAfOJIl1qEvRf2uq3BiKxmh6Fh5pfp2ieyek7Kg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/abi": "5.8.0", - "@ethersproject/abstract-provider": "5.8.0", - "@ethersproject/abstract-signer": "5.8.0", - "@ethersproject/address": "5.8.0", - "@ethersproject/base64": "5.8.0", - "@ethersproject/basex": "5.8.0", - "@ethersproject/bignumber": "5.8.0", - "@ethersproject/bytes": "5.8.0", - "@ethersproject/constants": "5.8.0", - "@ethersproject/contracts": "5.8.0", - "@ethersproject/hash": "5.8.0", - "@ethersproject/hdnode": "5.8.0", - "@ethersproject/json-wallets": "5.8.0", - "@ethersproject/keccak256": "5.8.0", - "@ethersproject/logger": "5.8.0", - "@ethersproject/networks": "5.8.0", - "@ethersproject/pbkdf2": "5.8.0", - "@ethersproject/properties": "5.8.0", - "@ethersproject/providers": "5.8.0", - "@ethersproject/random": "5.8.0", - "@ethersproject/rlp": "5.8.0", - "@ethersproject/sha2": "5.8.0", - "@ethersproject/signing-key": "5.8.0", - "@ethersproject/solidity": "5.8.0", - "@ethersproject/strings": "5.8.0", - "@ethersproject/transactions": "5.8.0", - "@ethersproject/units": "5.8.0", - "@ethersproject/wallet": "5.8.0", - "@ethersproject/web": "5.8.0", - "@ethersproject/wordlists": "5.8.0" - } - }, - "node_modules/eventemitter3": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", - "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/expect-utils": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fastfile": { - "version": "0.0.20", - "resolved": "https://registry.npmjs.org/fastfile/-/fastfile-0.0.20.tgz", - "integrity": "sha512-r5ZDbgImvVWCP0lA/cGNgQcZqR+aYdFx3u+CtJqUE510pBUVGMn4ulL/iRTI4tACTYsNJ736uzFxEBXesPAktA==", - "license": "GPL-3.0" - }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/ffjavascript": { - "version": "0.2.63", - "resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.2.63.tgz", - "integrity": "sha512-dBgdsfGks58b66JnUZeZpGxdMIDQ4QsD3VYlRJyFVrKQHb2kJy4R2gufx5oetrTxXPT+aEjg0dOvOLg1N0on4A==", - "dev": true, - "license": "GPL-3.0", - "dependencies": { - "wasmbuilder": "0.0.16", - "wasmcurves": "0.2.2", - "web-worker": "1.2.0" - } - }, - "node_modules/filelist": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.6.tgz", - "integrity": "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==", - "license": "Apache-2.0", - "dependencies": { - "minimatch": "^5.0.1" - } - }, - "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", - "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-east-asian-width": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", - "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/hoopy": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", - "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==", - "license": "MIT", - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true, - "license": "MIT" - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/husky": { - "version": "9.1.7", - "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", - "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", - "dev": true, - "license": "MIT", - "bin": { - "husky": "bin.js" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/typicode" - } - }, - "node_modules/import-local": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", - "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", - "dev": true, - "license": "MIT", - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", - "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", - "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/core": "^7.23.9", - "@babel/parser": "^7.23.9", - "@istanbuljs/schema": "^0.1.3", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^7.5.4" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", - "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jake": { - "version": "10.9.4", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", - "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", - "license": "Apache-2.0", - "dependencies": { - "async": "^3.2.6", - "filelist": "^1.0.4", - "picocolors": "^1.1.1" - }, - "bin": { - "jake": "bin/cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", - "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/core": "^29.7.0", - "@jest/types": "^29.6.3", - "import-local": "^3.0.2", - "jest-cli": "^29.7.0" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-changed-files": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", - "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", - "dev": true, - "license": "MIT", - "dependencies": { - "execa": "^5.0.0", - "jest-util": "^29.7.0", - "p-limit": "^3.1.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", - "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^1.0.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.7.0", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "p-limit": "^3.1.0", - "pretty-format": "^29.7.0", - "pure-rand": "^6.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-cli": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", - "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/core": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "create-jest": "^29.7.0", - "exit": "^0.1.2", - "import-local": "^3.0.2", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-config": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", - "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-jest": "^29.7.0", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.7.0", - "jest-environment-node": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-diff": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", - "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-docblock": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", - "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", - "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "jest-util": "^29.7.0", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-node": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", - "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-haste-map": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", - "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-leak-detector": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", - "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", - "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", - "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.6.3", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-mock": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", - "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", - "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", - "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "resolve": "^1.20.0", - "resolve.exports": "^2.0.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", - "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-regex-util": "^29.6.3", - "jest-snapshot": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", - "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/environment": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.7.0", - "jest-environment-node": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-leak-detector": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-resolve": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-util": "^29.7.0", - "jest-watcher": "^29.7.0", - "jest-worker": "^29.7.0", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", - "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/globals": "^29.7.0", - "@jest/source-map": "^29.6.3", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", - "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "natural-compare": "^1.4.0", - "pretty-format": "^29.7.0", - "semver": "^7.5.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", - "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", - "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "leven": "^3.1.0", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watcher": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", - "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.7.0", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", - "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "jest-util": "^29.7.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/js-sha3": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", - "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", - "license": "MIT" - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", - "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true, - "license": "MIT" - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonpath": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsonpath/-/jsonpath-1.3.0.tgz", - "integrity": "sha512-0kjkYHJBkAy50Z5QzArZ7udmvxrJzkpKYW27fiF//BrMY7TQibYLl+FYIXN2BiYmwMIVzSfD8aDRj6IzgBX2/w==", - "license": "MIT", - "dependencies": { - "esprima": "1.2.5", - "static-eval": "2.1.1", - "underscore": "1.13.6" - } - }, - "node_modules/jsonpath/node_modules/esprima": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz", - "integrity": "sha512-S9VbPDU0adFErpDai3qDkjq8+G05ONtKzcyNrPKg/ZKa+tf879nX2KexNU95b31UoTJjRLInNBHHHjFPoCd7lQ==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, - "license": "MIT" - }, - "node_modules/lint-staged": { - "version": "15.2.11", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.11.tgz", - "integrity": "sha512-Ev6ivCTYRTGs9ychvpVw35m/bcNDuBN+mnTeObCL5h+boS5WzBEC6LHI4I9F/++sZm1m+J2LEiy0gxL/R9TBqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "~5.3.0", - "commander": "~12.1.0", - "debug": "~4.4.0", - "execa": "~8.0.1", - "lilconfig": "~3.1.3", - "listr2": "~8.2.5", - "micromatch": "~4.0.8", - "pidtree": "~0.6.0", - "string-argv": "~0.3.2", - "yaml": "~2.6.1" - }, - "bin": { - "lint-staged": "bin/lint-staged.js" - }, - "engines": { - "node": ">=18.12.0" - }, - "funding": { - "url": "https://opencollective.com/lint-staged" - } - }, - "node_modules/lint-staged/node_modules/chalk": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/lint-staged/node_modules/execa": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", - "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/lint-staged/node_modules/get-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", - "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lint-staged/node_modules/human-signals": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", - "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=16.17.0" - } - }, - "node_modules/lint-staged/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lint-staged/node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lint-staged/node_modules/npm-run-path": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", - "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lint-staged/node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lint-staged/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lint-staged/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/lint-staged/node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/listr2": { - "version": "8.2.5", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.5.tgz", - "integrity": "sha512-iyAZCeyD+c1gPyE9qpFu8af0Y+MRtmKOncdGoA2S5EY8iFq99dmmvkNnHiWo+pj0s7yH7l3KPIgee77tKpXPWQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "cli-truncate": "^4.0.0", - "colorette": "^2.0.20", - "eventemitter3": "^5.0.1", - "log-update": "^6.1.0", - "rfdc": "^1.4.1", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true, - "license": "MIT" - }, - "node_modules/log-update": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", - "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-escapes": "^7.0.0", - "cli-cursor": "^5.0.0", - "slice-ansi": "^7.1.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/ansi-escapes": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", - "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", - "dev": true, - "license": "MIT", - "dependencies": { - "environment": "^1.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/log-update/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/log-update/node_modules/is-fullwidth-code-point": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", - "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.3.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/slice-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", - "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "is-fullwidth-code-point": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/log-update/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/logplease": { - "version": "1.2.15", - "resolved": "https://registry.npmjs.org/logplease/-/logplease-1.2.15.tgz", - "integrity": "sha512-jLlHnlsPSJjpwUfcNyUxXCl33AYg2cHhIf9QhGL2T4iPT0XPB+xP1LRKFPgIg1M/sg9kAJvy94w9CzBNrfnstA==", - "license": "MIT" - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, - "license": "ISC" - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true, - "license": "MIT" - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/mimic-function": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", - "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true, - "license": "ISC" - }, - "node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", - "dev": true, - "license": "MIT" - }, - "node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/nanoassert": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-2.0.0.tgz", - "integrity": "sha512-7vO7n28+aYO4J+8w96AzhmU8G+Y/xpPDJz/se19ICsqj/momRbb9mh9ZUtkoJ5X3nTnPdhEJyc0qnM6yAsHBaA==", - "license": "ISC" - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/node-addon-api": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", - "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", - "dev": true, - "license": "MIT" - }, - "node_modules/node-gyp-build": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", - "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", - "dev": true, - "license": "MIT", - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/node-releases": { - "version": "2.0.36", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", - "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", - "dev": true, - "license": "MIT" - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-locate/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pidtree": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", - "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", - "dev": true, - "license": "MIT", - "bin": { - "pidtree": "bin/pidtree.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/pirates": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", - "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/prettier": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", - "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pure-rand": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", - "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "license": "MIT" - }, - "node_modules/r1csfile": { - "version": "0.0.48", - "resolved": "https://registry.npmjs.org/r1csfile/-/r1csfile-0.0.48.tgz", - "integrity": "sha512-kHRkKUJNaor31l05f2+RFzvcH5XSa7OfEfd/l4hzjte6NL6fjRkSMfZ4BjySW9wmfdwPOtq3mXurzPvPGEf5Tw==", - "license": "GPL-3.0", - "dependencies": { - "@iden3/bigarray": "0.0.2", - "@iden3/binfileutils": "0.0.12", - "fastfile": "0.0.20", - "ffjavascript": "0.3.0" - } - }, - "node_modules/r1csfile/node_modules/ffjavascript": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.3.0.tgz", - "integrity": "sha512-l7sR5kmU3gRwDy8g0Z2tYBXy5ttmafRPFOqY7S6af5cq51JqJWt5eQ/lSR/rs2wQNbDYaYlQr5O+OSUf/oMLoQ==", - "license": "GPL-3.0", - "dependencies": { - "wasmbuilder": "0.0.16", - "wasmcurves": "0.2.2", - "web-worker": "1.2.0" - } - }, - "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve.exports": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", - "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/restore-cursor": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", - "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", - "dev": true, - "license": "MIT", - "dependencies": { - "onetime": "^7.0.0", - "signal-exit": "^4.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/restore-cursor/node_modules/onetime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", - "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-function": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/restore-cursor/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rfdc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", - "dev": true, - "license": "MIT" - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/scrypt-js": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", - "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", - "dev": true, - "license": "MIT" - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true, - "license": "MIT" - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", - "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.0.0", - "is-fullwidth-code-point": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/snarkjs": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/snarkjs/-/snarkjs-0.7.5.tgz", - "integrity": "sha512-h+3c4rXZKLhLuHk4LHydZCk/h5GcNvk5GjVKRRkHmfb6Ntf8gHOA9zea3g656iclRuhqQ3iKDWFgiD9ypLrKiA==", - "license": "GPL-3.0", - "dependencies": { - "@iden3/binfileutils": "0.0.12", - "bfj": "^7.0.2", - "blake2b-wasm": "^2.4.0", - "circom_runtime": "0.1.28", - "ejs": "^3.1.6", - "fastfile": "0.0.20", - "ffjavascript": "0.3.1", - "js-sha3": "^0.8.0", - "logplease": "^1.2.15", - "r1csfile": "0.0.48" - }, - "bin": { - "snarkjs": "build/cli.cjs" - } - }, - "node_modules/snarkjs/node_modules/ffjavascript": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.3.1.tgz", - "integrity": "sha512-4PbK1WYodQtuF47D4pRI5KUg3Q392vuP5WjE1THSnceHdXwU3ijaoS0OqxTzLknCtz4Z2TtABzkBdBdMn3B/Aw==", - "license": "GPL-3.0", - "dependencies": { - "wasmbuilder": "0.0.16", - "wasmcurves": "0.2.2", - "web-worker": "1.2.0" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "devOptional": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/static-eval": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.1.1.tgz", - "integrity": "sha512-MgWpQ/ZjGieSVB3eOJVs4OA2LT/q1vx98KPCTTQPzq/aLr0YUXTsgryTXr4SLfR0ZfUUCiedM9n/ABeDIyy4mA==", - "license": "MIT", - "dependencies": { - "escodegen": "^2.1.0" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-argv": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", - "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6.19" - } - }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "license": "ISC", - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tryer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", - "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==", - "license": "MIT" - }, - "node_modules/ts-jest": { - "version": "29.2.5", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.5.tgz", - "integrity": "sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "bs-logger": "^0.2.6", - "ejs": "^3.1.10", - "fast-json-stable-stringify": "^2.1.0", - "jest-util": "^29.0.0", - "json5": "^2.2.3", - "lodash.memoize": "^4.1.2", - "make-error": "^1.3.6", - "semver": "^7.6.3", - "yargs-parser": "^21.1.1" - }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.0.0-beta.0 <8", - "@jest/transform": "^29.0.0", - "@jest/types": "^29.0.0", - "babel-jest": "^29.0.0", - "jest": "^29.0.0", - "typescript": ">=4.3 <6" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@jest/transform": { - "optional": true - }, - "@jest/types": { - "optional": true - }, - "babel-jest": { - "optional": true - }, - "esbuild": { - "optional": true - } - } - }, - "node_modules/ts-jest/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/underscore": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", - "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", - "license": "MIT" - }, - "node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, - "license": "MIT" - }, - "node_modules/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/v8-to-istanbul": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", - "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", - "dev": true, - "license": "ISC", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^2.0.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "makeerror": "1.0.12" - } - }, - "node_modules/wasmbuilder": { - "version": "0.0.16", - "resolved": "https://registry.npmjs.org/wasmbuilder/-/wasmbuilder-0.0.16.tgz", - "integrity": "sha512-Qx3lEFqaVvp1cEYW7Bfi+ebRJrOiwz2Ieu7ZG2l7YyeSJIok/reEQCQCuicj/Y32ITIJuGIM9xZQppGx5LrQdA==", - "license": "GPL-3.0" - }, - "node_modules/wasmcurves": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/wasmcurves/-/wasmcurves-0.2.2.tgz", - "integrity": "sha512-JRY908NkmKjFl4ytnTu5ED6AwPD+8VJ9oc94kdq7h5bIwbj0L4TDJ69mG+2aLs2SoCmGfqIesMWTEJjtYsoQXQ==", - "license": "GPL-3.0", - "dependencies": { - "wasmbuilder": "0.0.16" - } - }, - "node_modules/web-worker": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.2.0.tgz", - "integrity": "sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==", - "license": "Apache-2.0" - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - }, - "node_modules/yaml": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.1.tgz", - "integrity": "sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==", - "dev": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/yargs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/package.json b/package.json index ac7f0d7..3ab3325 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@orbinum/proof-generator", - "version": "3.3.2", + "version": "3.5.0", "description": "ZK-SNARK proof generator for Orbinum. Combines snarkjs (witness) with arkworks WASM (proof generation) to produce 128-byte Groth16 proofs.", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -17,19 +17,16 @@ }, "scripts": { "build": "tsc", - "test": "jest", - "test:watch": "jest --watch", - "test:verbose": "jest --verbose", - "test:shield": "jest shielded.test.ts", - "test:unshield": "jest unshield.test.ts", - "test:transfer": "jest transfer.test.ts", - "test:disclosure": "jest disclosure.test.ts", + "test": "vitest run", + "test:watch": "vitest", + "test:coverage": "vitest run --coverage", "format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"", "format:check": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"", + "typecheck": "tsc --project tsconfig.test.json --noEmit", "lint": "tsc --project tsconfig.test.json --noEmit", - "prepare": "husky", - "prepublishOnly": "npm run build && npm run lint && npm test", - "clean": "rm -rf dist node_modules package-lock.json" + "check": "pnpm lint && pnpm typecheck && pnpm format:check && pnpm build && pnpm test", + "prepublishOnly": "pnpm check", + "clean": "rm -rf dist node_modules package-lock.json pnpm-lock.yaml" }, "keywords": [ "zksnark", @@ -42,24 +39,22 @@ "orbinum" ], "dependencies": { - "@orbinum/circuits": "^0.4.2", - "@orbinum/groth16-proofs": "^2.0.0", - "snarkjs": "0.7.5" + "@orbinum/circuits": "0.4.4", + "@orbinum/groth16-proofs": "3.0.0", + "snarkjs": "0.7.6" }, "devDependencies": { "@types/circomlibjs": "0.1.6", - "@types/jest": "29.5.14", - "@types/node": "22.10.5", + "@types/node": "25.5.2", "@types/snarkjs": "0.7.9", + "@vitest/coverage-v8": "4.1.3", "circomlibjs": "0.1.7", - "husky": "9.1.7", - "jest": "29.7.0", - "lint-staged": "15.2.11", - "prettier": "3.4.2", - "ts-jest": "29.2.5", - "typescript": "^5.7.3" + "prettier": "3.8.1", + "typescript": "6.0.2", + "vitest": "4.1.3" }, "engines": { "node": ">=22.0.0" - } + }, + "packageManager": "pnpm@10.32.1+sha512.a706938f0e89ac1456b6563eab4edf1d1faf3368d1191fc5c59790e96dc918e4456ab2e67d613de1043d2e8c81f87303e6b40d4ffeca9df15ef1ad567348f2be" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..2720462 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,1825 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@orbinum/circuits': + specifier: 0.4.4 + version: 0.4.4 + '@orbinum/groth16-proofs': + specifier: 3.0.0 + version: 3.0.0 + snarkjs: + specifier: 0.7.6 + version: 0.7.6 + devDependencies: + '@types/circomlibjs': + specifier: 0.1.6 + version: 0.1.6 + '@types/node': + specifier: 25.5.2 + version: 25.5.2 + '@types/snarkjs': + specifier: 0.7.9 + version: 0.7.9 + '@vitest/coverage-v8': + specifier: 4.1.3 + version: 4.1.3(vitest@4.1.3) + circomlibjs: + specifier: 0.1.7 + version: 0.1.7 + prettier: + specifier: 3.8.1 + version: 3.8.1 + typescript: + specifier: 6.0.2 + version: 6.0.2 + vitest: + specifier: 4.1.3 + version: 4.1.3(@types/node@25.5.2)(@vitest/coverage-v8@4.1.3)(vite@8.0.7(@types/node@25.5.2)) + +packages: + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.2': + resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} + + '@bcoe/v8-coverage@1.0.2': + resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} + engines: {node: '>=18'} + + '@emnapi/core@1.9.1': + resolution: {integrity: sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==} + + '@emnapi/runtime@1.9.1': + resolution: {integrity: sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==} + + '@emnapi/wasi-threads@1.2.0': + resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==} + + '@ethersproject/abi@5.8.0': + resolution: {integrity: sha512-b9YS/43ObplgyV6SlyQsG53/vkSal0MNA1fskSC4mbnCMi8R+NkcH8K9FPYNESf6jUefBUniE4SOKms0E/KK1Q==} + + '@ethersproject/abstract-provider@5.8.0': + resolution: {integrity: sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg==} + + '@ethersproject/abstract-signer@5.8.0': + resolution: {integrity: sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA==} + + '@ethersproject/address@5.8.0': + resolution: {integrity: sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA==} + + '@ethersproject/base64@5.8.0': + resolution: {integrity: sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ==} + + '@ethersproject/basex@5.8.0': + resolution: {integrity: sha512-PIgTszMlDRmNwW9nhS6iqtVfdTAKosA7llYXNmGPw4YAI1PUyMv28988wAb41/gHF/WqGdoLv0erHaRcHRKW2Q==} + + '@ethersproject/bignumber@5.8.0': + resolution: {integrity: sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA==} + + '@ethersproject/bytes@5.8.0': + resolution: {integrity: sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==} + + '@ethersproject/constants@5.8.0': + resolution: {integrity: sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg==} + + '@ethersproject/contracts@5.8.0': + resolution: {integrity: sha512-0eFjGz9GtuAi6MZwhb4uvUM216F38xiuR0yYCjKJpNfSEy4HUM8hvqqBj9Jmm0IUz8l0xKEhWwLIhPgxNY0yvQ==} + + '@ethersproject/hash@5.8.0': + resolution: {integrity: sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA==} + + '@ethersproject/hdnode@5.8.0': + resolution: {integrity: sha512-4bK1VF6E83/3/Im0ERnnUeWOY3P1BZml4ZD3wcH8Ys0/d1h1xaFt6Zc+Dh9zXf9TapGro0T4wvO71UTCp3/uoA==} + + '@ethersproject/json-wallets@5.8.0': + resolution: {integrity: sha512-HxblNck8FVUtNxS3VTEYJAcwiKYsBIF77W15HufqlBF9gGfhmYOJtYZp8fSDZtn9y5EaXTE87zDwzxRoTFk11w==} + + '@ethersproject/keccak256@5.8.0': + resolution: {integrity: sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng==} + + '@ethersproject/logger@5.8.0': + resolution: {integrity: sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==} + + '@ethersproject/networks@5.8.0': + resolution: {integrity: sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg==} + + '@ethersproject/pbkdf2@5.8.0': + resolution: {integrity: sha512-wuHiv97BrzCmfEaPbUFpMjlVg/IDkZThp9Ri88BpjRleg4iePJaj2SW8AIyE8cXn5V1tuAaMj6lzvsGJkGWskg==} + + '@ethersproject/properties@5.8.0': + resolution: {integrity: sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw==} + + '@ethersproject/providers@5.8.0': + resolution: {integrity: sha512-3Il3oTzEx3o6kzcg9ZzbE+oCZYyY+3Zh83sKkn4s1DZfTUjIegHnN2Cm0kbn9YFy45FDVcuCLLONhU7ny0SsCw==} + + '@ethersproject/random@5.8.0': + resolution: {integrity: sha512-E4I5TDl7SVqyg4/kkA/qTfuLWAQGXmSOgYyO01So8hLfwgKvYK5snIlzxJMk72IFdG/7oh8yuSqY2KX7MMwg+A==} + + '@ethersproject/rlp@5.8.0': + resolution: {integrity: sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q==} + + '@ethersproject/sha2@5.8.0': + resolution: {integrity: sha512-dDOUrXr9wF/YFltgTBYS0tKslPEKr6AekjqDW2dbn1L1xmjGR+9GiKu4ajxovnrDbwxAKdHjW8jNcwfz8PAz4A==} + + '@ethersproject/signing-key@5.8.0': + resolution: {integrity: sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w==} + + '@ethersproject/solidity@5.8.0': + resolution: {integrity: sha512-4CxFeCgmIWamOHwYN9d+QWGxye9qQLilpgTU0XhYs1OahkclF+ewO+3V1U0mvpiuQxm5EHHmv8f7ClVII8EHsA==} + + '@ethersproject/strings@5.8.0': + resolution: {integrity: sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg==} + + '@ethersproject/transactions@5.8.0': + resolution: {integrity: sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg==} + + '@ethersproject/units@5.8.0': + resolution: {integrity: sha512-lxq0CAnc5kMGIiWW4Mr041VT8IhNM+Pn5T3haO74XZWFulk7wH1Gv64HqE96hT4a7iiNMdOCFEBgaxWuk8ETKQ==} + + '@ethersproject/wallet@5.8.0': + resolution: {integrity: sha512-G+jnzmgg6UxurVKRKvw27h0kvG75YKXZKdlLYmAHeF32TGUzHkOFd7Zn6QHOTYRFWnfjtSSFjBowKo7vfrXzPA==} + + '@ethersproject/web@5.8.0': + resolution: {integrity: sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw==} + + '@ethersproject/wordlists@5.8.0': + resolution: {integrity: sha512-2df9bbXicZws2Sb5S6ET493uJ0Z84Fjr3pC4tu/qlnZERibZCeUVuqdtt+7Tv9xxhUxHoIekIA7avrKUWHrezg==} + + '@iden3/bigarray@0.0.2': + resolution: {integrity: sha512-Xzdyxqm1bOFF6pdIsiHLLl3HkSLjbhqJHVyqaTxXt3RqXBEnmsUmEW47H7VOi/ak7TdkRpNkxjyK5Zbkm+y52g==} + + '@iden3/binfileutils@0.0.12': + resolution: {integrity: sha512-naAmzuDufRIcoNfQ1d99d7hGHufLA3wZSibtr4dMe6ZeiOPV1KwOZWTJ1YVz4HbaWlpDuzVU72dS4ATQS4PXBQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@napi-rs/wasm-runtime@1.1.3': + resolution: {integrity: sha512-xK9sGVbJWYb08+mTJt3/YV24WxvxpXcXtP6B172paPZ+Ts69Re9dAr7lKwJoeIx8OoeuimEiRZ7umkiUVClmmQ==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + + '@noble/hashes@1.8.0': + resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} + engines: {node: ^14.21.3 || >=16} + + '@orbinum/circuits@0.4.4': + resolution: {integrity: sha512-AP5+ULtr2r8FNSnSWYqAMDsRQdhXeUzJztXHrHueFpj4NA7k/slMHa8ieqSUUPZHHDcVAxGjFTKpssGbHzGlYw==} + engines: {node: '>=18.0.0'} + + '@orbinum/groth16-proofs@3.0.0': + resolution: {integrity: sha512-1I8/wMkCKn5zpS4qVoaXnUfNiuHoo7Ym8hlG6avaijGtITLY6BzLEcwjBjVHZ2vpI+CjL557ORfyjuGrFDzJSw==} + engines: {node: '>=18.0.0'} + + '@oxc-project/types@0.123.0': + resolution: {integrity: sha512-YtECP/y8Mj1lSHiUWGSRzy/C6teUKlS87dEfuVKT09LgQbUsBW1rNg+MiJ4buGu3yuADV60gbIvo9/HplA56Ew==} + + '@rolldown/binding-android-arm64@1.0.0-rc.13': + resolution: {integrity: sha512-5ZiiecKH2DXAVJTNN13gNMUcCDg4Jy8ZjbXEsPnqa248wgOVeYRX0iqXXD5Jz4bI9BFHgKsI2qmyJynstbmr+g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.0-rc.13': + resolution: {integrity: sha512-tz/v/8G77seu8zAB3A5sK3UFoOl06zcshEzhUO62sAEtrEuW/H1CcyoupOrD+NbQJytYgA4CppXPzlrmp4JZKA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.0-rc.13': + resolution: {integrity: sha512-8DakphqOz8JrMYWTJmWA+vDJxut6LijZ8Xcdc4flOlAhU7PNVwo2MaWBF9iXjJAPo5rC/IxEFZDhJ3GC7NHvug==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.0-rc.13': + resolution: {integrity: sha512-4wBQFfjDuXYN/SVI8inBF3Aa+isq40rc6VMFbk5jcpolUBTe5cYnMsHZ51nFWsx3PVyyNN3vgoESki0Hmr/4BA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.13': + resolution: {integrity: sha512-JW/e4yPIXLms+jmnbwwy5LA/LxVwZUWLN8xug+V200wzaVi5TEGIWQlh8o91gWYFxW609euI98OCCemmWGuPrw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.13': + resolution: {integrity: sha512-ZfKWpXiUymDnavepCaM6KG/uGydJ4l2nBmMxg60Ci4CbeefpqjPWpfaZM7PThOhk2dssqBAcwLc6rAyr0uTdXg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.13': + resolution: {integrity: sha512-bmRg3O6Z0gq9yodKKWCIpnlH051sEfdVwt+6m5UDffAQMUUqU0xjnQqqAUm+Gu7ofAAly9DqiQDtKu2nPDEABA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.13': + resolution: {integrity: sha512-8Wtnbw4k7pMYN9B/mOEAsQ8HOiq7AZ31Ig4M9BKn2So4xRaFEhtCSa4ZJaOutOWq50zpgR4N5+L/opnlaCx8wQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.13': + resolution: {integrity: sha512-D/0Nlo8mQuxSMohNJUF2lDXWRsFDsHldfRRgD9bRgktj+EndGPj4DOV37LqDKPYS+osdyhZEH7fTakTAEcW7qg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.13': + resolution: {integrity: sha512-eRrPvat2YaVQcwwKi/JzOP6MKf1WRnOCr+VaI3cTWz3ZoLcP/654z90lVCJ4dAuMEpPdke0n+qyAqXDZdIC4rA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-musl@1.0.0-rc.13': + resolution: {integrity: sha512-PsdONiFRp8hR8KgVjTWjZ9s7uA3uueWL0t74/cKHfM4dR5zXYv4AjB8BvA+QDToqxAFg4ZkcVEqeu5F7inoz5w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rolldown/binding-openharmony-arm64@1.0.0-rc.13': + resolution: {integrity: sha512-hCNXgC5dI3TVOLrPT++PKFNZ+1EtS0mLQwfXXXSUD/+rGlB65gZDwN/IDuxLpQP4x8RYYHqGomlUXzpO8aVI2w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.0-rc.13': + resolution: {integrity: sha512-viLS5C5et8NFtLWw9Sw3M/w4vvnVkbWkO7wSNh3C+7G1+uCkGpr6PcjNDSFcNtmXY/4trjPBqUfcOL+P3sWy/g==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.13': + resolution: {integrity: sha512-Fqa3Tlt1xL4wzmAYxGNFV36Hb+VfPc9PYU+E25DAnswXv3ODDu/yyWjQDbXMo5AGWkQVjLgQExuVu8I/UaZhPQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.13': + resolution: {integrity: sha512-/pLI5kPkGEi44TDlnbio3St/5gUFeN51YWNAk/Gnv6mEQBOahRBh52qVFVBpmrnU01n2yysvBML9Ynu7K4kGAQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.0-rc.13': + resolution: {integrity: sha512-3ngTAv6F/Py35BsYbeeLeecvhMKdsKm4AoOETVhAA+Qc8nrA2I0kF7oa93mE9qnIurngOSpMnQ0x2nQY2FPviA==} + + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/circomlibjs@0.1.6': + resolution: {integrity: sha512-yF174bPDaiKgejlZzCSqKwZaqXhlxMcVEHrAtstFohwP05OjtvHXOdxO6HQeTg8WwIdgMg7MJb1WyWZdUCGlPQ==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/node@25.5.2': + resolution: {integrity: sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg==} + + '@types/snarkjs@0.7.9': + resolution: {integrity: sha512-pb4Bq3GI2YQOQOG0dR/YuQs/mqcuL6k/vnz68LIPtpA2frrUL3twf69a3AUK9eUmNNeW0RIKkq6scDlC75Is+g==} + + '@vitest/coverage-v8@4.1.3': + resolution: {integrity: sha512-/MBdrkA8t6hbdCWFKs09dPik774xvs4Z6L4bycdCxYNLHM8oZuRyosumQMG19LUlBsB6GeVpL1q4kFFazvyKGA==} + peerDependencies: + '@vitest/browser': 4.1.3 + vitest: 4.1.3 + peerDependenciesMeta: + '@vitest/browser': + optional: true + + '@vitest/expect@4.1.3': + resolution: {integrity: sha512-CW8Q9KMtXDGHj0vCsqui0M5KqRsu0zm0GNDW7Gd3U7nZ2RFpPKSCpeCXoT+/+5zr1TNlsoQRDEz+LzZUyq6gnQ==} + + '@vitest/mocker@4.1.3': + resolution: {integrity: sha512-XN3TrycitDQSzGRnec/YWgoofkYRhouyVQj4YNsJ5r/STCUFqMrP4+oxEv3e7ZbLi4og5kIHrZwekDJgw6hcjw==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@4.1.3': + resolution: {integrity: sha512-hYqqwuMbpkkBodpRh4k4cQSOELxXky1NfMmQvOfKvV8zQHz8x8Dla+2wzElkMkBvSAJX5TRGHJAQvK0TcOafwg==} + + '@vitest/runner@4.1.3': + resolution: {integrity: sha512-VwgOz5MmT0KhlUj40h02LWDpUBVpflZ/b7xZFA25F29AJzIrE+SMuwzFf0b7t4EXdwRNX61C3B6auIXQTR3ttA==} + + '@vitest/snapshot@4.1.3': + resolution: {integrity: sha512-9l+k/J9KG5wPJDX9BcFFzhhwNjwkRb8RsnYhaT1vPY7OufxmQFc9sZzScRCPTiETzl37mrIWVY9zxzmdVeJwDQ==} + + '@vitest/spy@4.1.3': + resolution: {integrity: sha512-ujj5Uwxagg4XUIfAUyRQxAg631BP6e9joRiN99mr48Bg9fRs+5mdUElhOoZ6rP5mBr8Bs3lmrREnkrQWkrsTCw==} + + '@vitest/utils@4.1.3': + resolution: {integrity: sha512-Pc/Oexse/khOWsGB+w3q4yzA4te7W4gpZZAvk+fr8qXfTURZUMj5i7kuxsNK5mP/dEB6ao3jfr0rs17fHhbHdw==} + + aes-js@3.0.0: + resolution: {integrity: sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + ast-v8-to-istanbul@1.0.0: + resolution: {integrity: sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==} + + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + + b4a@1.8.0: + resolution: {integrity: sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==} + peerDependencies: + react-native-b4a: '*' + peerDependenciesMeta: + react-native-b4a: + optional: true + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + bech32@1.1.4: + resolution: {integrity: sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==} + + bfj@7.1.0: + resolution: {integrity: sha512-I6MMLkn+anzNdCUp9hMRyui1HaNEUCco50lxbvNS4+EyXg8lN3nJ48PjPWtbH8UVS9CuMoaKE9U2V3l29DaRQw==} + engines: {node: '>= 8.0.0'} + + blake-hash@2.0.0: + resolution: {integrity: sha512-Igj8YowDu1PRkRsxZA7NVkdFNxH5rKv5cpLxQ0CVXSIA77pVYwCPRQJ2sMew/oneUpfuYRyjG6r8SmmmnbZb1w==} + engines: {node: '>= 10'} + + blake2b-wasm@2.4.0: + resolution: {integrity: sha512-S1kwmW2ZhZFFFOghcx73+ZajEfKBqhP82JMssxtLVMxlaPea1p9uoLiUZ5WYyHn0KddwbLc+0vh4wR0KBNoT5w==} + + blake2b@2.1.4: + resolution: {integrity: sha512-AyBuuJNI64gIvwx13qiICz6H6hpmjvYS5DGkG6jbXMOT8Z3WUJ3V1X0FlhIoT1b/5JtHE3ki+xjtMvu1nn+t9A==} + + bluebird@3.7.2: + resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + + bn.js@4.12.3: + resolution: {integrity: sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==} + + bn.js@5.2.3: + resolution: {integrity: sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==} + + brace-expansion@2.0.3: + resolution: {integrity: sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==} + + brorand@1.1.0: + resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} + + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + engines: {node: '>=18'} + + check-types@11.2.3: + resolution: {integrity: sha512-+67P1GkJRaxQD6PKK0Et9DhwQB+vGg3PM5+aavopCpZT1lj9jeqfvpgTLAWErNj8qApkkmXlu/Ug74kmhagkXg==} + + circom_runtime@0.1.28: + resolution: {integrity: sha512-ACagpQ7zBRLKDl5xRZ4KpmYIcZDUjOiNRuxvXLqhnnlLSVY1Dbvh73TI853nqoR0oEbihtWmMSjgc5f+pXf/jQ==} + hasBin: true + + circomlibjs@0.1.7: + resolution: {integrity: sha512-GRAUoAlKAsiiTa+PA725G9RmEmJJRc8tRFxw/zKktUxlQISGznT4hH4ESvW8FNTsrGg/nNd06sGP/Wlx0LUHVg==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + ejs@3.1.10: + resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} + engines: {node: '>=0.10.0'} + hasBin: true + + elliptic@6.6.1: + resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} + + es-module-lexer@2.0.0: + resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} + + escodegen@2.1.0: + resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} + engines: {node: '>=6.0'} + hasBin: true + + esprima@1.2.5: + resolution: {integrity: sha512-S9VbPDU0adFErpDai3qDkjq8+G05ONtKzcyNrPKg/ZKa+tf879nX2KexNU95b31UoTJjRLInNBHHHjFPoCd7lQ==} + engines: {node: '>=0.4.0'} + hasBin: true + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + ethers@5.8.0: + resolution: {integrity: sha512-DUq+7fHrCg1aPDFCHx6UIPb3nmt2XMpM7Y/g2gLhsl3lIBqeAfOJIl1qEvRf2uq3BiKxmh6Fh5pfp2ieyek7Kg==} + + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + engines: {node: '>=12.0.0'} + + fastfile@0.0.20: + resolution: {integrity: sha512-r5ZDbgImvVWCP0lA/cGNgQcZqR+aYdFx3u+CtJqUE510pBUVGMn4ulL/iRTI4tACTYsNJ736uzFxEBXesPAktA==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + ffjavascript@0.2.63: + resolution: {integrity: sha512-dBgdsfGks58b66JnUZeZpGxdMIDQ4QsD3VYlRJyFVrKQHb2kJy4R2gufx5oetrTxXPT+aEjg0dOvOLg1N0on4A==} + + ffjavascript@0.3.0: + resolution: {integrity: sha512-l7sR5kmU3gRwDy8g0Z2tYBXy5ttmafRPFOqY7S6af5cq51JqJWt5eQ/lSR/rs2wQNbDYaYlQr5O+OSUf/oMLoQ==} + + ffjavascript@0.3.1: + resolution: {integrity: sha512-4PbK1WYodQtuF47D4pRI5KUg3Q392vuP5WjE1THSnceHdXwU3ijaoS0OqxTzLknCtz4Z2TtABzkBdBdMn3B/Aw==} + + filelist@1.0.6: + resolution: {integrity: sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + hash.js@1.1.7: + resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + + hmac-drbg@1.0.1: + resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + + hoopy@0.1.4: + resolution: {integrity: sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==} + engines: {node: '>= 6.0.0'} + + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-reports@3.2.0: + resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} + engines: {node: '>=8'} + + jake@10.9.4: + resolution: {integrity: sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==} + engines: {node: '>=10'} + hasBin: true + + js-sha3@0.8.0: + resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} + + js-tokens@10.0.0: + resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} + + jsonpath@1.3.0: + resolution: {integrity: sha512-0kjkYHJBkAy50Z5QzArZ7udmvxrJzkpKYW27fiF//BrMY7TQibYLl+FYIXN2BiYmwMIVzSfD8aDRj6IzgBX2/w==} + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + logplease@1.2.15: + resolution: {integrity: sha512-jLlHnlsPSJjpwUfcNyUxXCl33AYg2cHhIf9QhGL2T4iPT0XPB+xP1LRKFPgIg1M/sg9kAJvy94w9CzBNrfnstA==} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + magicast@0.5.2: + resolution: {integrity: sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + + minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + + minimalistic-crypto-utils@1.0.1: + resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + + minimatch@5.1.9: + resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} + engines: {node: '>=10'} + + nanoassert@2.0.0: + resolution: {integrity: sha512-7vO7n28+aYO4J+8w96AzhmU8G+Y/xpPDJz/se19ICsqj/momRbb9mh9ZUtkoJ5X3nTnPdhEJyc0qnM6yAsHBaA==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + node-addon-api@3.2.1: + resolution: {integrity: sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==} + + node-gyp-build@4.8.4: + resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} + hasBin: true + + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + + postcss@8.5.9: + resolution: {integrity: sha512-7a70Nsot+EMX9fFU3064K/kdHWZqGVY+BADLyXc8Dfv+mTLLVl6JzJpPaCZ2kQL9gIJvKXSLMHhqdRRjwQeFtw==} + engines: {node: ^10 || ^12 || >=14} + + prettier@3.8.1: + resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} + engines: {node: '>=14'} + hasBin: true + + r1csfile@0.0.48: + resolution: {integrity: sha512-kHRkKUJNaor31l05f2+RFzvcH5XSa7OfEfd/l4hzjte6NL6fjRkSMfZ4BjySW9wmfdwPOtq3mXurzPvPGEf5Tw==} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + rolldown@1.0.0-rc.13: + resolution: {integrity: sha512-bvVj8YJmf0rq4pSFmH7laLa6pYrhghv3PRzrCdRAr23g66zOKVJ4wkvFtgohtPLWmthgg8/rkaqRHrpUEh0Zbw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + scrypt-js@3.0.1: + resolution: {integrity: sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==} + + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + engines: {node: '>=10'} + hasBin: true + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + snarkjs@0.7.6: + resolution: {integrity: sha512-4uH1xA5JzVU5jaaWS2fXej3+RC6L5Erhr6INTJtUA27du4Elbh4VXCeeRjB4QiwL6N6y7SNKePw5prTxyEf4Zg==} + hasBin: true + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + static-eval@2.1.1: + resolution: {integrity: sha512-MgWpQ/ZjGieSVB3eOJVs4OA2LT/q1vx98KPCTTQPzq/aLr0YUXTsgryTXr4SLfR0ZfUUCiedM9n/ABeDIyy4mA==} + + std-env@4.0.0: + resolution: {integrity: sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@1.1.1: + resolution: {integrity: sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==} + engines: {node: '>=18'} + + tinyglobby@0.2.16: + resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} + engines: {node: '>=12.0.0'} + + tinyrainbow@3.1.0: + resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} + engines: {node: '>=14.0.0'} + + tryer@1.0.1: + resolution: {integrity: sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + typescript@6.0.2: + resolution: {integrity: sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==} + engines: {node: '>=14.17'} + hasBin: true + + underscore@1.13.6: + resolution: {integrity: sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==} + + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + vite@8.0.7: + resolution: {integrity: sha512-P1PbweD+2/udplnThz3btF4cf6AgPky7kk23RtHUkJIU5BIxwPprhRGmOAHs6FTI7UiGbTNrgNP6jSYD6JaRnw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.0 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@4.1.3: + resolution: {integrity: sha512-DBc4Tx0MPNsqb9isoyOq00lHftVx/KIU44QOm2q59npZyLUkENn8TMFsuzuO+4U2FUa9rgbbPt3udrP25GcjXw==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.1.3 + '@vitest/browser-preview': 4.1.3 + '@vitest/browser-webdriverio': 4.1.3 + '@vitest/coverage-istanbul': 4.1.3 + '@vitest/coverage-v8': 4.1.3 + '@vitest/ui': 4.1.3 + happy-dom: '*' + jsdom: '*' + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + wasmbuilder@0.0.16: + resolution: {integrity: sha512-Qx3lEFqaVvp1cEYW7Bfi+ebRJrOiwz2Ieu7ZG2l7YyeSJIok/reEQCQCuicj/Y32ITIJuGIM9xZQppGx5LrQdA==} + + wasmcurves@0.2.2: + resolution: {integrity: sha512-JRY908NkmKjFl4ytnTu5ED6AwPD+8VJ9oc94kdq7h5bIwbj0L4TDJ69mG+2aLs2SoCmGfqIesMWTEJjtYsoQXQ==} + + web-worker@1.2.0: + resolution: {integrity: sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==} + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + +snapshots: + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/parser@7.29.2': + dependencies: + '@babel/types': 7.29.0 + + '@babel/types@7.29.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@bcoe/v8-coverage@1.0.2': {} + + '@emnapi/core@1.9.1': + dependencies: + '@emnapi/wasi-threads': 1.2.0 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.9.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@ethersproject/abi@5.8.0': + dependencies: + '@ethersproject/address': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/hash': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/strings': 5.8.0 + + '@ethersproject/abstract-provider@5.8.0': + dependencies: + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/networks': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/transactions': 5.8.0 + '@ethersproject/web': 5.8.0 + + '@ethersproject/abstract-signer@5.8.0': + dependencies: + '@ethersproject/abstract-provider': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + + '@ethersproject/address@5.8.0': + dependencies: + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/rlp': 5.8.0 + + '@ethersproject/base64@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + + '@ethersproject/basex@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/properties': 5.8.0 + + '@ethersproject/bignumber@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + bn.js: 5.2.3 + + '@ethersproject/bytes@5.8.0': + dependencies: + '@ethersproject/logger': 5.8.0 + + '@ethersproject/constants@5.8.0': + dependencies: + '@ethersproject/bignumber': 5.8.0 + + '@ethersproject/contracts@5.8.0': + dependencies: + '@ethersproject/abi': 5.8.0 + '@ethersproject/abstract-provider': 5.8.0 + '@ethersproject/abstract-signer': 5.8.0 + '@ethersproject/address': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/transactions': 5.8.0 + + '@ethersproject/hash@5.8.0': + dependencies: + '@ethersproject/abstract-signer': 5.8.0 + '@ethersproject/address': 5.8.0 + '@ethersproject/base64': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/strings': 5.8.0 + + '@ethersproject/hdnode@5.8.0': + dependencies: + '@ethersproject/abstract-signer': 5.8.0 + '@ethersproject/basex': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/pbkdf2': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/sha2': 5.8.0 + '@ethersproject/signing-key': 5.8.0 + '@ethersproject/strings': 5.8.0 + '@ethersproject/transactions': 5.8.0 + '@ethersproject/wordlists': 5.8.0 + + '@ethersproject/json-wallets@5.8.0': + dependencies: + '@ethersproject/abstract-signer': 5.8.0 + '@ethersproject/address': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/hdnode': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/pbkdf2': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/random': 5.8.0 + '@ethersproject/strings': 5.8.0 + '@ethersproject/transactions': 5.8.0 + aes-js: 3.0.0 + scrypt-js: 3.0.1 + + '@ethersproject/keccak256@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + js-sha3: 0.8.0 + + '@ethersproject/logger@5.8.0': {} + + '@ethersproject/networks@5.8.0': + dependencies: + '@ethersproject/logger': 5.8.0 + + '@ethersproject/pbkdf2@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/sha2': 5.8.0 + + '@ethersproject/properties@5.8.0': + dependencies: + '@ethersproject/logger': 5.8.0 + + '@ethersproject/providers@5.8.0': + dependencies: + '@ethersproject/abstract-provider': 5.8.0 + '@ethersproject/abstract-signer': 5.8.0 + '@ethersproject/address': 5.8.0 + '@ethersproject/base64': 5.8.0 + '@ethersproject/basex': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/hash': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/networks': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/random': 5.8.0 + '@ethersproject/rlp': 5.8.0 + '@ethersproject/sha2': 5.8.0 + '@ethersproject/strings': 5.8.0 + '@ethersproject/transactions': 5.8.0 + '@ethersproject/web': 5.8.0 + bech32: 1.1.4 + ws: 8.18.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@ethersproject/random@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + + '@ethersproject/rlp@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + + '@ethersproject/sha2@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + hash.js: 1.1.7 + + '@ethersproject/signing-key@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + bn.js: 5.2.3 + elliptic: 6.6.1 + hash.js: 1.1.7 + + '@ethersproject/solidity@5.8.0': + dependencies: + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/sha2': 5.8.0 + '@ethersproject/strings': 5.8.0 + + '@ethersproject/strings@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/logger': 5.8.0 + + '@ethersproject/transactions@5.8.0': + dependencies: + '@ethersproject/address': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/rlp': 5.8.0 + '@ethersproject/signing-key': 5.8.0 + + '@ethersproject/units@5.8.0': + dependencies: + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/logger': 5.8.0 + + '@ethersproject/wallet@5.8.0': + dependencies: + '@ethersproject/abstract-provider': 5.8.0 + '@ethersproject/abstract-signer': 5.8.0 + '@ethersproject/address': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/hash': 5.8.0 + '@ethersproject/hdnode': 5.8.0 + '@ethersproject/json-wallets': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/random': 5.8.0 + '@ethersproject/signing-key': 5.8.0 + '@ethersproject/transactions': 5.8.0 + '@ethersproject/wordlists': 5.8.0 + + '@ethersproject/web@5.8.0': + dependencies: + '@ethersproject/base64': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/strings': 5.8.0 + + '@ethersproject/wordlists@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/hash': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/strings': 5.8.0 + + '@iden3/bigarray@0.0.2': {} + + '@iden3/binfileutils@0.0.12': + dependencies: + fastfile: 0.0.20 + ffjavascript: 0.3.1 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@napi-rs/wasm-runtime@1.1.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)': + dependencies: + '@emnapi/core': 1.9.1 + '@emnapi/runtime': 1.9.1 + '@tybys/wasm-util': 0.10.1 + optional: true + + '@noble/hashes@1.8.0': {} + + '@orbinum/circuits@0.4.4': {} + + '@orbinum/groth16-proofs@3.0.0': {} + + '@oxc-project/types@0.123.0': {} + + '@rolldown/binding-android-arm64@1.0.0-rc.13': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.0-rc.13': + optional: true + + '@rolldown/binding-darwin-x64@1.0.0-rc.13': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.0-rc.13': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.13': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.13': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.13': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.13': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.13': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.13': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.0-rc.13': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.0-rc.13': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.0-rc.13': + dependencies: + '@emnapi/core': 1.9.1 + '@emnapi/runtime': 1.9.1 + '@napi-rs/wasm-runtime': 1.1.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1) + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.13': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.13': + optional: true + + '@rolldown/pluginutils@1.0.0-rc.13': {} + + '@standard-schema/spec@1.1.0': {} + + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/circomlibjs@0.1.6': {} + + '@types/deep-eql@4.0.2': {} + + '@types/estree@1.0.8': {} + + '@types/node@25.5.2': + dependencies: + undici-types: 7.18.2 + + '@types/snarkjs@0.7.9': {} + + '@vitest/coverage-v8@4.1.3(vitest@4.1.3)': + dependencies: + '@bcoe/v8-coverage': 1.0.2 + '@vitest/utils': 4.1.3 + ast-v8-to-istanbul: 1.0.0 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-reports: 3.2.0 + magicast: 0.5.2 + obug: 2.1.1 + std-env: 4.0.0 + tinyrainbow: 3.1.0 + vitest: 4.1.3(@types/node@25.5.2)(@vitest/coverage-v8@4.1.3)(vite@8.0.7(@types/node@25.5.2)) + + '@vitest/expect@4.1.3': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.1.3 + '@vitest/utils': 4.1.3 + chai: 6.2.2 + tinyrainbow: 3.1.0 + + '@vitest/mocker@4.1.3(vite@8.0.7(@types/node@25.5.2))': + dependencies: + '@vitest/spy': 4.1.3 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 8.0.7(@types/node@25.5.2) + + '@vitest/pretty-format@4.1.3': + dependencies: + tinyrainbow: 3.1.0 + + '@vitest/runner@4.1.3': + dependencies: + '@vitest/utils': 4.1.3 + pathe: 2.0.3 + + '@vitest/snapshot@4.1.3': + dependencies: + '@vitest/pretty-format': 4.1.3 + '@vitest/utils': 4.1.3 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@4.1.3': {} + + '@vitest/utils@4.1.3': + dependencies: + '@vitest/pretty-format': 4.1.3 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.0 + + aes-js@3.0.0: {} + + assertion-error@2.0.1: {} + + ast-v8-to-istanbul@1.0.0: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + estree-walker: 3.0.3 + js-tokens: 10.0.0 + + async@3.2.6: {} + + b4a@1.8.0: {} + + balanced-match@1.0.2: {} + + bech32@1.1.4: {} + + bfj@7.1.0: + dependencies: + bluebird: 3.7.2 + check-types: 11.2.3 + hoopy: 0.1.4 + jsonpath: 1.3.0 + tryer: 1.0.1 + + blake-hash@2.0.0: + dependencies: + node-addon-api: 3.2.1 + node-gyp-build: 4.8.4 + readable-stream: 3.6.2 + + blake2b-wasm@2.4.0: + dependencies: + b4a: 1.8.0 + nanoassert: 2.0.0 + transitivePeerDependencies: + - react-native-b4a + + blake2b@2.1.4: + dependencies: + blake2b-wasm: 2.4.0 + nanoassert: 2.0.0 + transitivePeerDependencies: + - react-native-b4a + + bluebird@3.7.2: {} + + bn.js@4.12.3: {} + + bn.js@5.2.3: {} + + brace-expansion@2.0.3: + dependencies: + balanced-match: 1.0.2 + + brorand@1.1.0: {} + + chai@6.2.2: {} + + check-types@11.2.3: {} + + circom_runtime@0.1.28: + dependencies: + ffjavascript: 0.3.1 + + circomlibjs@0.1.7: + dependencies: + blake-hash: 2.0.0 + blake2b: 2.1.4 + ethers: 5.8.0 + ffjavascript: 0.2.63 + transitivePeerDependencies: + - bufferutil + - react-native-b4a + - utf-8-validate + + convert-source-map@2.0.0: {} + + detect-libc@2.1.2: {} + + ejs@3.1.10: + dependencies: + jake: 10.9.4 + + elliptic@6.6.1: + dependencies: + bn.js: 4.12.3 + brorand: 1.1.0 + hash.js: 1.1.7 + hmac-drbg: 1.0.1 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + + es-module-lexer@2.0.0: {} + + escodegen@2.1.0: + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionalDependencies: + source-map: 0.6.1 + + esprima@1.2.5: {} + + esprima@4.0.1: {} + + estraverse@5.3.0: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + + esutils@2.0.3: {} + + ethers@5.8.0: + dependencies: + '@ethersproject/abi': 5.8.0 + '@ethersproject/abstract-provider': 5.8.0 + '@ethersproject/abstract-signer': 5.8.0 + '@ethersproject/address': 5.8.0 + '@ethersproject/base64': 5.8.0 + '@ethersproject/basex': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/contracts': 5.8.0 + '@ethersproject/hash': 5.8.0 + '@ethersproject/hdnode': 5.8.0 + '@ethersproject/json-wallets': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/networks': 5.8.0 + '@ethersproject/pbkdf2': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/providers': 5.8.0 + '@ethersproject/random': 5.8.0 + '@ethersproject/rlp': 5.8.0 + '@ethersproject/sha2': 5.8.0 + '@ethersproject/signing-key': 5.8.0 + '@ethersproject/solidity': 5.8.0 + '@ethersproject/strings': 5.8.0 + '@ethersproject/transactions': 5.8.0 + '@ethersproject/units': 5.8.0 + '@ethersproject/wallet': 5.8.0 + '@ethersproject/web': 5.8.0 + '@ethersproject/wordlists': 5.8.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + expect-type@1.3.0: {} + + fastfile@0.0.20: {} + + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + + ffjavascript@0.2.63: + dependencies: + wasmbuilder: 0.0.16 + wasmcurves: 0.2.2 + web-worker: 1.2.0 + + ffjavascript@0.3.0: + dependencies: + wasmbuilder: 0.0.16 + wasmcurves: 0.2.2 + web-worker: 1.2.0 + + ffjavascript@0.3.1: + dependencies: + wasmbuilder: 0.0.16 + wasmcurves: 0.2.2 + web-worker: 1.2.0 + + filelist@1.0.6: + dependencies: + minimatch: 5.1.9 + + fsevents@2.3.3: + optional: true + + has-flag@4.0.0: {} + + hash.js@1.1.7: + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + + hmac-drbg@1.0.1: + dependencies: + hash.js: 1.1.7 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + + hoopy@0.1.4: {} + + html-escaper@2.0.2: {} + + inherits@2.0.4: {} + + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-reports@3.2.0: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + + jake@10.9.4: + dependencies: + async: 3.2.6 + filelist: 1.0.6 + picocolors: 1.1.1 + + js-sha3@0.8.0: {} + + js-tokens@10.0.0: {} + + jsonpath@1.3.0: + dependencies: + esprima: 1.2.5 + static-eval: 2.1.1 + underscore: 1.13.6 + + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + logplease@1.2.15: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + magicast@0.5.2: + dependencies: + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + source-map-js: 1.2.1 + + make-dir@4.0.0: + dependencies: + semver: 7.7.4 + + minimalistic-assert@1.0.1: {} + + minimalistic-crypto-utils@1.0.1: {} + + minimatch@5.1.9: + dependencies: + brace-expansion: 2.0.3 + + nanoassert@2.0.0: {} + + nanoid@3.3.11: {} + + node-addon-api@3.2.1: {} + + node-gyp-build@4.8.4: {} + + obug@2.1.1: {} + + pathe@2.0.3: {} + + picocolors@1.1.1: {} + + picomatch@4.0.4: {} + + postcss@8.5.9: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prettier@3.8.1: {} + + r1csfile@0.0.48: + dependencies: + '@iden3/bigarray': 0.0.2 + '@iden3/binfileutils': 0.0.12 + fastfile: 0.0.20 + ffjavascript: 0.3.0 + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + rolldown@1.0.0-rc.13: + dependencies: + '@oxc-project/types': 0.123.0 + '@rolldown/pluginutils': 1.0.0-rc.13 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.0-rc.13 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.13 + '@rolldown/binding-darwin-x64': 1.0.0-rc.13 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.13 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.13 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.13 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.13 + '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.13 + '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.13 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.13 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.13 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.13 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.13 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.13 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.13 + + safe-buffer@5.2.1: {} + + scrypt-js@3.0.1: {} + + semver@7.7.4: {} + + siginfo@2.0.0: {} + + snarkjs@0.7.6: + dependencies: + '@iden3/binfileutils': 0.0.12 + '@noble/hashes': 1.8.0 + bfj: 7.1.0 + circom_runtime: 0.1.28 + ejs: 3.1.10 + fastfile: 0.0.20 + ffjavascript: 0.3.1 + logplease: 1.2.15 + r1csfile: 0.0.48 + + source-map-js@1.2.1: {} + + source-map@0.6.1: + optional: true + + stackback@0.0.2: {} + + static-eval@2.1.1: + dependencies: + escodegen: 2.1.0 + + std-env@4.0.0: {} + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + tinybench@2.9.0: {} + + tinyexec@1.1.1: {} + + tinyglobby@0.2.16: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + tinyrainbow@3.1.0: {} + + tryer@1.0.1: {} + + tslib@2.8.1: + optional: true + + typescript@6.0.2: {} + + underscore@1.13.6: {} + + undici-types@7.18.2: {} + + util-deprecate@1.0.2: {} + + vite@8.0.7(@types/node@25.5.2): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.9 + rolldown: 1.0.0-rc.13 + tinyglobby: 0.2.16 + optionalDependencies: + '@types/node': 25.5.2 + fsevents: 2.3.3 + + vitest@4.1.3(@types/node@25.5.2)(@vitest/coverage-v8@4.1.3)(vite@8.0.7(@types/node@25.5.2)): + dependencies: + '@vitest/expect': 4.1.3 + '@vitest/mocker': 4.1.3(vite@8.0.7(@types/node@25.5.2)) + '@vitest/pretty-format': 4.1.3 + '@vitest/runner': 4.1.3 + '@vitest/snapshot': 4.1.3 + '@vitest/spy': 4.1.3 + '@vitest/utils': 4.1.3 + es-module-lexer: 2.0.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.4 + std-env: 4.0.0 + tinybench: 2.9.0 + tinyexec: 1.1.1 + tinyglobby: 0.2.16 + tinyrainbow: 3.1.0 + vite: 8.0.7(@types/node@25.5.2) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 25.5.2 + '@vitest/coverage-v8': 4.1.3(vitest@4.1.3) + transitivePeerDependencies: + - msw + + wasmbuilder@0.0.16: {} + + wasmcurves@0.2.2: + dependencies: + wasmbuilder: 0.0.16 + + web-worker@1.2.0: {} + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + ws@8.18.0: {} diff --git a/scripts/benchmark.ts b/scripts/benchmark.ts new file mode 100644 index 0000000..13a518b --- /dev/null +++ b/scripts/benchmark.ts @@ -0,0 +1,452 @@ +/** + * Benchmark: proof generation times across all circuits and both backends. + * + * Run with: + * npx tsx scripts/benchmark.ts + */ + +// @ts-ignore +import { buildPoseidon, buildEddsa } from 'circomlibjs'; +import * as snarkjs from 'snarkjs'; +import { generateProof } from '../src/generate'; +import { NodeArtifactProvider } from '../src/providers'; +import { CircuitType } from '../src/circuits/types'; +import { generateProofFromWitnessWasm, compressSnarkjsProofWasm } from '../src/wasm/loader'; +import { getCircuitConfig } from '../src/circuits/config'; + +const RUNS = 3; +const provider = new NodeArtifactProvider(); + +// ── Helpers ────────────────────────────────────────────────────────────────── + +function median(times: number[]): number { + const sorted = [...times].sort((a, b) => a - b); + return sorted[Math.floor(sorted.length / 2)]; +} + +function avg(times: number[]): number { + return Math.round(times.reduce((s, t) => s + t, 0) / times.length); +} + +async function bench( + label: string, + circuitType: CircuitType, + inputs: Record, + backend: 'snarkjs' | 'arkworks' +): Promise { + const times: number[] = []; + process.stdout.write(` ${label.padEnd(45)}`); + + for (let i = 0; i < RUNS; i++) { + const t0 = Date.now(); + await generateProof(circuitType, inputs as any, { provider, backend }); + times.push(Date.now() - t0); + process.stdout.write('.'); + } + + const med = median(times); + const mean = avg(times); + console.log( + ` med=${med}ms avg=${mean}ms runs=[${times.join(', ')}]ms` + ); + return times; +} + +// ── Input builders ──────────────────────────────────────────────────────────── + +async function buildDisclosureInputs(poseidon: any) { + const F = poseidon.F; + const value = 1_000_000n; + const ownerPubkey = 0x1234567890abcdefn; + const blinding = 0xdeadbeefcafebaben; + const assetId = 1n; + const commitment: bigint = F.toObject(poseidon([value, assetId, ownerPubkey, blinding])); + return { + commitment: commitment.toString(), + revealed_value: value.toString(), + revealed_asset_id: assetId.toString(), + revealed_owner_hash: '0', + value: value.toString(), + asset_id: assetId.toString(), + owner_pubkey: ownerPubkey.toString(), + blinding: blinding.toString(), + disclose_value: '1', + disclose_asset_id: '1', + disclose_owner: '0', + }; +} + +async function buildPrivateLinkInputs(poseidon: any) { + const F = poseidon.F; + // private_link: commitment = Poseidon(Poseidon(chain_id_fe, address_fe), blinding_fe) + const chainIdFe = 1000n; // chain id as field element + const addressFe = 0x1234567890abcdefn; // address bytes as LE field element + const blindingFe = 0xdeadbeefcafebaben; + const callHashFe = 0x9988776655443322n; + + const inner: bigint = F.toObject(poseidon([chainIdFe, addressFe])); + const commitment: bigint = F.toObject(poseidon([inner, blindingFe])); + + return { + commitment: commitment.toString(), + call_hash_fe: callHashFe.toString(), + chain_id_fe: chainIdFe.toString(), + address_fe: addressFe.toString(), + blinding_fe: blindingFe.toString(), + }; +} + +async function buildUnshieldInputs(poseidon: any) { + const F = poseidon.F; + const DEPTH = 20; + + const noteValue = 1_000_000n; + const noteAssetId = 1n; + const noteOwner = 0x1234567890abcdefn; + const noteBlinding = 0xdeadbeefcafebaben; + const spendingKey = 0x9999n; + const recipient = 0x742d35cc6634c0532925a3b844bc454e4438f44en; + + // commitment = Poseidon4(value, asset_id, owner_pubkey, blinding) + const commitment: bigint = F.toObject(poseidon([noteValue, noteAssetId, noteOwner, noteBlinding])); + + // nullifier = Poseidon2(commitment, spending_key) + const nullifier: bigint = F.toObject(poseidon([commitment, spendingKey])); + + // Merkle proof: note at position 0 — all path_indices = 0, all path_elements = 0 + // root = Poseidon2^20(commitment, 0, 0, ...) going up from leaf + let merkleRoot: bigint = commitment; + for (let i = 0; i < DEPTH; i++) { + merkleRoot = F.toObject(poseidon([merkleRoot, 0n])); + } + + return { + merkle_root: merkleRoot.toString(), + nullifier: nullifier.toString(), + amount: noteValue.toString(), + recipient: recipient.toString(), + asset_id: noteAssetId.toString(), + note_value: noteValue.toString(), + note_asset_id: noteAssetId.toString(), + note_owner: noteOwner.toString(), + note_blinding: noteBlinding.toString(), + spending_key: spendingKey.toString(), + path_elements: Array(DEPTH).fill('0'), + path_indices: Array(DEPTH).fill('0'), + }; +} + +async function buildTransferInputs(poseidon: any, eddsa: any) { + const F = poseidon.F; + const DEPTH = 20; + const assetId = 1n; + + // Two input notes, equal value so sum is conserved + const inputValues = [500_000n, 500_000n]; + const inputBlindings = [0xdeadbeef01n, 0xdeadbeef02n]; + const spendingKeys = [0x1111n, 0x2222n]; + + // EdDSA keypairs per input note owner + const prvKeys = [Buffer.alloc(32), Buffer.alloc(32)]; + prvKeys[0][0] = 1; + prvKeys[1][0] = 2; + const pubKeys = prvKeys.map(pk => eddsa.prv2pub(pk)); + const ownerAx = pubKeys.map((pk: any) => eddsa.F.toObject(pk[0]) as bigint); + const ownerAy = pubKeys.map((pk: any) => eddsa.F.toObject(pk[1]) as bigint); + + // Input commitments: Poseidon4(value, asset_id, owner_pubkey=Ax, blinding) + const inputCommitments = inputValues.map((v, i) => + F.toObject(poseidon([v, assetId, ownerAx[i], inputBlindings[i]])) as bigint + ); + + // EdDSA signatures over each input commitment + const sigs = inputCommitments.map((c: bigint, i: number) => + eddsa.signPoseidon(prvKeys[i], eddsa.F.e(c)) + ); + + // Nullifiers: Poseidon2(commitment, spending_key) + const nullifiers = inputCommitments.map((c: bigint, i: number) => + F.toObject(poseidon([c, spendingKeys[i]])) as bigint + ); + + // Merkle tree with 2 leaves: + // position 0: inputCommitments[0] (left) + // position 1: inputCommitments[1] (right) + // root = Poseidon2^19(...Poseidon2(c0, c1)..., 0) + let merkleRoot: bigint = F.toObject(poseidon([inputCommitments[0], inputCommitments[1]])); + for (let i = 0; i < DEPTH - 1; i++) { + merkleRoot = F.toObject(poseidon([merkleRoot, 0n])); + } + + // Path for note 0 (position 0): sibling at level 0 = c1, rest zero + const pathElements0 = [inputCommitments[1].toString(), ...Array(DEPTH - 1).fill('0')]; + const pathIndices0 = Array(DEPTH).fill('0'); + + // Path for note 1 (position 1): path_index[0]=1 (it's right child), sibling = c0 + const pathElements1 = [inputCommitments[0].toString(), ...Array(DEPTH - 1).fill('0')]; + const pathIndices1 = ['1', ...Array(DEPTH - 1).fill('0')]; + + // Output notes: same total value, different blindings/owners + const outputValues = [500_000n, 500_000n]; + const outputBlindings = [0xfeed01n, 0xfeed02n]; + const outputOwnerPubkeys = [0x9876n, 0x5432n]; + const outputCommitments = outputValues.map((v, i) => + F.toObject(poseidon([v, assetId, outputOwnerPubkeys[i], outputBlindings[i]])) as bigint + ); + + return { + merkle_root: merkleRoot.toString(), + nullifiers: nullifiers.map((n: bigint) => n.toString()), + commitments: outputCommitments.map((c: bigint) => c.toString()), + input_values: inputValues.map(v => v.toString()), + input_asset_ids: [assetId.toString(), assetId.toString()], + input_blindings: inputBlindings.map(b => b.toString()), + spending_keys: spendingKeys.map(k => k.toString()), + input_owner_Ax: ownerAx.map((v: bigint) => v.toString()), + input_owner_Ay: ownerAy.map((v: bigint) => v.toString()), + input_sig_R8x: sigs.map((s: any) => eddsa.F.toObject(s.R8[0]).toString()), + input_sig_R8y: sigs.map((s: any) => eddsa.F.toObject(s.R8[1]).toString()), + input_sig_S: sigs.map((s: any) => s.S.toString()), + input_path_elements: [pathElements0, pathElements1], + input_path_indices: [pathIndices0, pathIndices1], + output_values: outputValues.map(v => v.toString()), + output_asset_ids: [assetId.toString(), assetId.toString()], + output_owner_pubkeys: outputOwnerPubkeys.map(v => v.toString()), + output_blindings: outputBlindings.map(b => b.toString()), + }; +} + +// ── Per-phase timing ───────────────────────────────────────────────────────── + +interface PhaseResult { + /** Artifact loading from disk (both backends) */ + loadMs: number; + /** snarkjs.wtns.calculate — arkworks only (0 for snarkjs: bundled in fullProve) */ + witnessMs: number; + /** wtns.exportJson + JSON.stringify — arkworks only (0 for snarkjs) */ + serializeMs: number; + /** arkworks: WASM groth16-prove (incl. PK deserialization) | snarkjs: fullProve (witness+proof) */ + proveMs: number; + /** compressSnarkjsProofWasm — snarkjs only (0 for arkworks: already compressed) */ + compressMs: number; + totalMs: number; +} + +/** + * Run one proof-generation cycle broken down into measurable phases. + * + * arkworks phases: load → witness → serialize → prove + * snarkjs phases: load → fullProve (witness+proof bundled) → compress + */ +async function benchPhased( + circuitType: CircuitType, + inputs: Record, + backend: 'snarkjs' | 'arkworks' +): Promise { + const config = getCircuitConfig(circuitType); + let t0: number; + + if (backend === 'arkworks') { + // Phase 1: read .wasm + .ark from disk in parallel + t0 = Date.now(); + const [wasmBinary, provingKeyBytes] = await Promise.all([ + provider.getCircuitWasm(circuitType), + provider.getCircuitProvingKey!(circuitType), + ]); + const loadMs = Date.now() - t0; + + // Phase 2: calculate witness inside the circuit WASM + t0 = Date.now(); + const wtnsBuffer: { type: 'mem'; data?: Uint8Array } = { type: 'mem' }; + await (snarkjs as any).wtns.calculate(inputs, wasmBinary, wtnsBuffer); + const witnessMs = Date.now() - t0; + + // Phase 3: export witness to decimal JSON (JS → WASM serialization cost) + t0 = Date.now(); + const witnessArray: bigint[] = await (snarkjs as any).wtns.exportJson(wtnsBuffer); + const witnessDecimalJson = JSON.stringify(witnessArray.map(v => v.toString())); + const serializeMs = Date.now() - t0; + + // Phase 4: prove inside groth16-proofs WASM + // (includes: parse JSON + decimal→field + PK deserialize + Groth16::prove) + t0 = Date.now(); + await generateProofFromWitnessWasm( + config.expectedPublicSignals, + witnessDecimalJson, + provingKeyBytes + ); + const proveMs = Date.now() - t0; + + return { + loadMs, witnessMs, serializeMs, proveMs, compressMs: 0, + totalMs: loadMs + witnessMs + serializeMs + proveMs, + }; + } else { + // Phase 1: read .wasm + .zkey from disk in parallel + t0 = Date.now(); + const [wasmBinary, zkeyBinary] = await Promise.all([ + provider.getCircuitWasm(circuitType), + provider.getCircuitZkey(circuitType), + ]); + const loadMs = Date.now() - t0; + + // Phase 2: snarkjs fullProve — witness generation + proof bundled together + t0 = Date.now(); + const { proof } = await snarkjs.groth16.fullProve(inputs as any, wasmBinary, zkeyBinary); + const proveMs = Date.now() - t0; + + // Phase 3: compress snarkjs ec-points to arkworks 128-byte format + t0 = Date.now(); + await compressSnarkjsProofWasm(proof as any); + const compressMs = Date.now() - t0; + + return { + loadMs, witnessMs: 0, serializeMs: 0, proveMs, compressMs, + totalMs: loadMs + proveMs + compressMs, + }; + } +} + +// ── Results table ───────────────────────────────────────────────────────────── + +interface BenchResult { + circuit: string; + backend: string; + median: number; + avg: number; + times: number[]; +} + +const results: BenchResult[] = []; + +async function record( + circuit: CircuitType, + circuitLabel: string, + inputs: Record, + backend: 'snarkjs' | 'arkworks' +) { + const label = `${circuitLabel} (${backend})`; + try { + const times = await bench(label, circuit, inputs, backend); + results.push({ circuit: circuitLabel, backend, median: median(times), avg: avg(times), times }); + } catch (err: any) { + console.log(` ${'SKIP'.padStart(45)} (${err.message.slice(0, 60)})`); + results.push({ circuit: circuitLabel, backend, median: -1, avg: -1, times: [] }); + } +} + +// ── Main ────────────────────────────────────────────────────────────────────── + +(async () => { + console.log('=== proof-generator benchmark ==='); + console.log(`Circuits: Disclosure, PrivateLink, Unshield, Transfer | Backends: snarkjs, arkworks | Runs: ${RUNS} each\n`); + + const poseidon = await buildPoseidon(); + const eddsa = await buildEddsa(); + const disclosureInputs = await buildDisclosureInputs(poseidon); + const privateLinkInputs = await buildPrivateLinkInputs(poseidon); + const unshieldInputs = await buildUnshieldInputs(poseidon); + const transferInputs = await buildTransferInputs(poseidon, eddsa); + + // Warm-up: first run loads WASM modules — exclude from results + console.log('Warm-up (excluded from results)...'); + await generateProof(CircuitType.Disclosure, disclosureInputs as any, { + provider, + backend: 'snarkjs', + }).catch(() => {}); + await generateProof(CircuitType.Disclosure, disclosureInputs as any, { + provider, + backend: 'arkworks', + }).catch(() => {}); + console.log('Done.\n'); + + console.log('Results (median / avg across 3 runs):'); + console.log('-'.repeat(80)); + + await record(CircuitType.Disclosure, 'Disclosure ', disclosureInputs, 'snarkjs'); + await record(CircuitType.Disclosure, 'Disclosure ', disclosureInputs, 'arkworks'); + await record(CircuitType.PrivateLink, 'PrivateLink', privateLinkInputs, 'snarkjs'); + await record(CircuitType.PrivateLink, 'PrivateLink', privateLinkInputs, 'arkworks'); + await record(CircuitType.Unshield, 'Unshield ', unshieldInputs, 'snarkjs'); + await record(CircuitType.Unshield, 'Unshield ', unshieldInputs, 'arkworks'); + await record(CircuitType.Transfer, 'Transfer ', transferInputs, 'snarkjs'); + await record(CircuitType.Transfer, 'Transfer ', transferInputs, 'arkworks'); + + // ── Summary table ──────────────────────────────────────────────────────────── + console.log('\n' + '='.repeat(80)); + console.log('SUMMARY'); + console.log('='.repeat(80)); + console.log( + `${'Circuit'.padEnd(14)} ${'Backend'.padEnd(10)} ${'Median (ms)'.padStart(12)} ${'Avg (ms)'.padStart(10)}` + ); + console.log('-'.repeat(50)); + + for (const r of results) { + if (r.median === -1) { + console.log(`${r.circuit.padEnd(14)} ${r.backend.padEnd(10)} ${'SKIP'.padStart(12)} ${'SKIP'.padStart(10)}`); + } else { + console.log( + `${r.circuit.padEnd(14)} ${r.backend.padEnd(10)} ${r.median.toString().padStart(12)} ${r.avg.toString().padStart(10)}` + ); + } + } + + // Speedup comparison + console.log('\nSpeedup (snarkjs → arkworks):'); + const circuits = [...new Set(results.map(r => r.circuit))]; + for (const c of circuits) { + const s = results.find(r => r.circuit === c && r.backend === 'snarkjs'); + const a = results.find(r => r.circuit === c && r.backend === 'arkworks'); + if (s && a && s.median > 0 && a.median > 0) { + const speedup = (s.median / a.median).toFixed(2); + const diff = s.median - a.median; + console.log(` ${c}: ${s.median}ms → ${a.median}ms (${speedup}x, ${diff > 0 ? '-' : '+'}${Math.abs(diff)}ms)`); + } + } + + // ── Phase breakdown (1 run per circuit × backend) ──────────────────────────── + console.log('\n' + '='.repeat(85)); + console.log('PHASE BREAKDOWN (1 run — shows where each backend spends its time)'); + console.log('='.repeat(85)); + console.log( + `${'Circuit'.padEnd(13)} ${'Backend'.padEnd(9)}` + + `${'Load'.padStart(8)} ${'Witness'.padStart(9)} ${'Serialize'.padStart(11)} ${'Prove'.padStart(10)} ${'Compress'.padStart(10)} ${'Total'.padStart(10)}` + ); + console.log( + ' Witness = snarkjs.wtns.calculate (arkworks only; bundled in Prove for snarkjs)' + ); + console.log( + ' Serialize = wtns.exportJson + JSON.stringify (arkworks only)' + ); + console.log( + ' Prove = groth16-proofs WASM prove (incl. PK deserializ.) OR snarkjs fullProve (witness+proof)' + ); + console.log( + ' Compress = compressSnarkjsProofWasm (snarkjs only)' + ); + console.log('-'.repeat(85)); + + const phaseCircuits: Array<{ type: CircuitType; label: string; inputs: Record }> = [ + { type: CircuitType.Disclosure, label: 'Disclosure', inputs: disclosureInputs }, + { type: CircuitType.PrivateLink, label: 'PrivateLink', inputs: privateLinkInputs }, + { type: CircuitType.Unshield, label: 'Unshield', inputs: unshieldInputs }, + { type: CircuitType.Transfer, label: 'Transfer', inputs: transferInputs }, + ]; + + for (const { type, label, inputs } of phaseCircuits) { + for (const be of ['snarkjs', 'arkworks'] as const) { + try { + const p = await benchPhased(type, inputs as any, be); + const ms = (v: number, w: number) => (v === 0 ? '—' : `${v}ms`).padStart(w); + console.log( + `${label.padEnd(13)} ${be.padEnd(9)}` + + `${ms(p.loadMs, 8)} ${ms(p.witnessMs, 9)} ${ms(p.serializeMs, 11)} ${ms(p.proveMs, 10)} ${ms(p.compressMs, 10)} ${ms(p.totalMs, 10)}` + ); + } catch (err: any) { + console.log(`${label.padEnd(13)} ${be.padEnd(9)} SKIP (${(err as Error).message.slice(0, 50)})`); + } + } + } + + console.log('\n=== Done ==='); +})(); diff --git a/src/circuits.ts b/src/circuits.ts deleted file mode 100644 index c6ba438..0000000 --- a/src/circuits.ts +++ /dev/null @@ -1,130 +0,0 @@ -/** - * Circuit Configuration and Artifact Providers - * - * Defines paths and metadata for all supported circuits. - * Implements ArtifactProvider for Node.js (fs) and Browser (fetch). - */ - -import { CircuitType, CircuitConfig } from './types'; -import { ArtifactProvider } from './provider'; -import * as path from 'path'; - -// ============================================================================ -// Defaults & Configuration -// ============================================================================ - -const DEFAULT_CIRCUIT_URL = 'https://circuits.orbinum.io/v1'; - -export function getCircuitConfig(circuitType: CircuitType): CircuitConfig { - const circuitName = circuitType.toLowerCase(); - return { - name: circuitName, - wasmPath: `${circuitName}.wasm`, - zkeyPath: `${circuitName}_pk.zkey`, - provingKeyPath: `${circuitName}_pk.ark`, - expectedPublicSignals: getExpectedPublicSignals(circuitType), - }; -} - -function getExpectedPublicSignals(circuitType: CircuitType): number { - switch (circuitType) { - case CircuitType.Unshield: - return 5; - case CircuitType.Transfer: - return 5; - case CircuitType.Disclosure: - return 4; - case CircuitType.PrivateLink: - return 2; - default: - throw new Error(`Unknown circuit type: ${circuitType}`); - } -} - -// ============================================================================ -// Node.js Provider (FS) -// ============================================================================ - -export class NodeArtifactProvider implements ArtifactProvider { - private fs: any; - private packageRoot: string; - - constructor(packageRoot?: string) { - // Dynamic require to avoid bundling fs in browser - try { - this.fs = eval('require')('fs'); - } catch (e) { - throw new Error('NodeArtifactProvider requires Node.js environment'); - } - this.packageRoot = packageRoot || this.resolvePackageRoot(); - } - - private resolvePackageRoot(): string { - const packageCandidates = ['@orbinum/circuits/package.json', 'orbinum-circuits/package.json']; - for (const candidate of packageCandidates) { - try { - return path.dirname(eval('require').resolve(candidate)); - } catch { - continue; - } - } - throw new Error('Cannot resolve @orbinum/circuits package'); - } - - async getCircuitWasm(type: CircuitType): Promise { - const config = getCircuitConfig(type); - const filePath = this.findArtifactPath(config.wasmPath); - return this.fs.readFileSync(filePath); - } - - async getCircuitZkey(type: CircuitType): Promise { - const config = getCircuitConfig(type); - const filePath = this.findArtifactPath(config.zkeyPath); - return this.fs.readFileSync(filePath); - } - - private findArtifactPath(filename: string): string { - const searchDirs = [ - this.packageRoot, - path.join(this.packageRoot, 'artifacts'), - path.join(this.packageRoot, 'pkg'), - ]; - for (const dir of searchDirs) { - const p = path.join(dir, filename); - if (this.fs.existsSync(p)) return p; - } - throw new Error(`Artifact ${filename} not found in ${this.packageRoot}`); - } -} - -// ============================================================================ -// Web Provider (Fetch) -// ============================================================================ - -export class WebArtifactProvider implements ArtifactProvider { - private baseUrl: string; - - constructor(baseUrl: string = DEFAULT_CIRCUIT_URL) { - this.baseUrl = baseUrl.replace(/\/$/, ''); - } - - async getCircuitWasm(type: CircuitType): Promise { - const config = getCircuitConfig(type); - return this.fetchArtifact(config.wasmPath); - } - - async getCircuitZkey(type: CircuitType): Promise { - const config = getCircuitConfig(type); - return this.fetchArtifact(config.zkeyPath); - } - - private async fetchArtifact(filename: string): Promise { - const url = `${this.baseUrl}/${filename}`; - const response = await fetch(url); - if (!response.ok) { - throw new Error(`Failed to fetch circuit artifact: ${url} (${response.status})`); - } - const buffer = await response.arrayBuffer(); - return new Uint8Array(buffer); - } -} diff --git a/src/circuits/config.ts b/src/circuits/config.ts new file mode 100644 index 0000000..53bbd37 --- /dev/null +++ b/src/circuits/config.ts @@ -0,0 +1,31 @@ +import { CircuitType, CircuitConfig } from './types'; + +/** + * Returns the circuit configuration (artifact filenames, expected public + * signals) for the given circuit type. + */ +export function getCircuitConfig(circuitType: CircuitType): CircuitConfig { + const name = circuitType.toLowerCase(); + return { + name, + wasmPath: `${name}.wasm`, + zkeyPath: `${name}_pk.zkey`, + provingKeyPath: `${name}_pk.ark`, + expectedPublicSignals: getExpectedPublicSignals(circuitType), + }; +} + +function getExpectedPublicSignals(circuitType: CircuitType): number { + switch (circuitType) { + case CircuitType.Unshield: + return 5; + case CircuitType.Transfer: + return 5; + case CircuitType.Disclosure: + return 4; + case CircuitType.PrivateLink: + return 2; + default: + throw new Error(`Unknown circuit type: ${circuitType}`); + } +} diff --git a/src/circuits/index.ts b/src/circuits/index.ts new file mode 100644 index 0000000..9129696 --- /dev/null +++ b/src/circuits/index.ts @@ -0,0 +1,2 @@ +export { getCircuitConfig } from './config'; +export * from './types'; diff --git a/src/circuits/types.ts b/src/circuits/types.ts new file mode 100644 index 0000000..ed1353f --- /dev/null +++ b/src/circuits/types.ts @@ -0,0 +1,37 @@ +/** Circuit types supported by Orbinum */ +export enum CircuitType { + Unshield = 'unshield', + Transfer = 'transfer', + Disclosure = 'disclosure', + PrivateLink = 'private_link', +} + +/** Circuit input value types (supports nested arrays for 2D inputs) */ +export type CircuitInputValue = string | number | string[] | number[] | string[][] | number[][]; + +/** Circuit input: any key-value pairs (circuit-specific) */ +export type CircuitInputs = Record; + +/** Proof generation result */ +export interface ProofResult { + /** Compressed proof bytes (128 bytes as hex string) */ + proof: string; + /** Public signals (circuit outputs) */ + publicSignals: string[]; + /** Circuit type used */ + circuitType: CircuitType; +} + +/** Circuit configuration */ +export interface CircuitConfig { + /** Circuit name (e.g., 'unshield') */ + name: string; + /** Path to WASM file */ + wasmPath: string; + /** Path to zkey proving key (snarkjs) */ + zkeyPath: string; + /** Path to .ark proving key (arkworks compressed format, for arkworks backend) */ + provingKeyPath: string; + /** Expected number of public signals */ + expectedPublicSignals: number; +} diff --git a/src/disclosure.ts b/src/disclosure/index.ts similarity index 91% rename from src/disclosure.ts rename to src/disclosure/index.ts index c44e016..f5fff9d 100644 --- a/src/disclosure.ts +++ b/src/disclosure/index.ts @@ -14,16 +14,13 @@ // @ts-ignore - circomlibjs has no type declarations import { buildPoseidon } from 'circomlibjs'; -import { generateProof, CircuitType } from './index'; -import { DisclosureMask, DisclosureProofOutput, ProofResult } from './types'; -import { - bigIntToHex, - bigIntToBytes32, - bytes32ToBigInt, - hexSignalToBigInt, - u64ToFieldStr, -} from './utils'; -import { ArtifactProvider } from './provider'; +import { generateProof } from '../generate'; +import { CircuitType, ProofResult } from '../circuits/types'; +import { bigIntToHex, hexSignalToBigInt, u64ToFieldStr } from '../utils'; +import { ArtifactProvider } from '../providers/interface'; +import { DisclosureMask, DisclosureProofOutput } from './types'; + +export type { DisclosureMask, DisclosureProofOutput } from './types'; // ============================================================================ // Internal: circuit input builder diff --git a/src/disclosure/types.ts b/src/disclosure/types.ts new file mode 100644 index 0000000..45cb537 --- /dev/null +++ b/src/disclosure/types.ts @@ -0,0 +1,36 @@ +/** + * Which fields to reveal to the auditor. + * + * At least one of `discloseValue`, `discloseAssetId`, or `discloseOwner` + * must be `true`. + */ +export interface DisclosureMask { + /** Reveal the note value (u64) */ + discloseValue: boolean; + /** Reveal the asset ID (u32) */ + discloseAssetId: boolean; + /** Reveal the owner identity hash (Poseidon(owner_pubkey)) */ + discloseOwner: boolean; +} + +/** Proof output returned by `generateDisclosureProof`. */ +export interface DisclosureProofOutput { + /** 128-byte compressed Groth16 proof as 0x-prefixed hex string */ + proof: string; + /** + * Raw public signals in hex (0x-prefixed, 32 bytes each). + * Order: [commitment, revealed_value, revealed_asset_id, revealed_owner_hash] + */ + publicSignals: string[]; + /** Human-readable revealed data */ + revealedData: { + /** Revealed note value as decimal string, or undefined if not disclosed */ + value?: string; + /** Revealed asset ID as number, or undefined if not disclosed */ + assetId?: number; + /** Revealed owner hash as 0x-prefixed hex, or undefined if not disclosed */ + ownerHash?: string; + /** Note commitment (always present) */ + commitment: string; + }; +} diff --git a/src/errors/index.ts b/src/errors/index.ts new file mode 100644 index 0000000..c8ebaa1 --- /dev/null +++ b/src/errors/index.ts @@ -0,0 +1,35 @@ +import { CircuitType } from '../circuits/types'; + +export class ProofGeneratorError extends Error { + constructor( + message: string, + public readonly code: string + ) { + super(message); + this.name = 'ProofGeneratorError'; + } +} + +export class WitnessCalculationError extends ProofGeneratorError { + constructor(message: string) { + super(message, 'WITNESS_CALCULATION_FAILED'); + } +} + +export class ProofGenerationError extends ProofGeneratorError { + constructor(message: string) { + super(message, 'PROOF_GENERATION_FAILED'); + } +} + +export class CircuitNotFoundError extends ProofGeneratorError { + constructor(circuitType: CircuitType) { + super(`Circuit not found: ${circuitType}`, 'CIRCUIT_NOT_FOUND'); + } +} + +export class InvalidInputsError extends ProofGeneratorError { + constructor(message: string) { + super(message, 'INVALID_INPUTS'); + } +} diff --git a/src/generate/backends/arkworks.ts b/src/generate/backends/arkworks.ts new file mode 100644 index 0000000..5744d50 --- /dev/null +++ b/src/generate/backends/arkworks.ts @@ -0,0 +1,60 @@ +import * as snarkjs from 'snarkjs'; +import { CircuitType, CircuitInputs, CircuitConfig } from '../../circuits/types'; +import { CircuitNotFoundError, ProofGenerationError } from '../../errors'; +import { ArtifactProvider } from '../../providers/interface'; +import { generateProofFromWitnessWasm } from '../../wasm/loader'; +import { validateProofSize } from '../../utils/validation'; + +/** + * Generates a Groth16 proof using the arkworks backend: + * calculates the witness with snarkjs (in-memory), then delegates + * proof generation to the arkworks WASM module via the .ark proving key. + */ +export async function runArkworksBackend( + circuitType: CircuitType, + inputs: CircuitInputs, + provider: ArtifactProvider, + config: CircuitConfig, + verbose: boolean +): Promise<{ proof: string; publicSignals: string[] }> { + let wasmBinary: Uint8Array | string; + let provingKeyBytes: Uint8Array; + + try { + if (verbose) console.log('[proof-generator] Fetching WASM + .ark proving key...'); + if (!provider.getCircuitProvingKey) { + throw new Error( + 'Provider does not support getCircuitProvingKey (required for arkworks backend)' + ); + } + [wasmBinary, provingKeyBytes] = await Promise.all([ + provider.getCircuitWasm(circuitType), + provider.getCircuitProvingKey(circuitType), + ]); + } catch (error) { + if (verbose) + console.error(`[proof-generator] Failed to load artifacts: ${(error as Error).message}`); + throw new CircuitNotFoundError(circuitType); + } + + try { + if (verbose) console.log('[proof-generator] Step 1: Calculating witness with snarkjs...'); + const wtnsBuffer: { type: 'mem'; data?: Uint8Array } = { type: 'mem' }; + await (snarkjs as any).wtns.calculate(inputs, wasmBinary, wtnsBuffer); + + if (verbose) console.log('[proof-generator] Step 2: Generating proof with arkworks WASM...'); + const witnessArray: bigint[] = await (snarkjs as any).wtns.exportJson(wtnsBuffer); + const witnessDecimalJson = JSON.stringify(witnessArray.map(v => v.toString())); + + const arkResult = await generateProofFromWitnessWasm( + config.expectedPublicSignals, + witnessDecimalJson, + provingKeyBytes + ); + validateProofSize(arkResult.proof); + + return arkResult; + } catch (error) { + throw new ProofGenerationError((error as Error).message); + } +} diff --git a/src/generate/backends/snarkjs.ts b/src/generate/backends/snarkjs.ts new file mode 100644 index 0000000..767e968 --- /dev/null +++ b/src/generate/backends/snarkjs.ts @@ -0,0 +1,64 @@ +import * as snarkjs from 'snarkjs'; +import { CircuitType, CircuitInputs, CircuitConfig } from '../../circuits/types'; +import { CircuitNotFoundError, ProofGenerationError } from '../../errors'; +import { ArtifactProvider } from '../../providers/interface'; +import { compressSnarkjsProofWasm } from '../../wasm/loader'; +import { validateProofSize } from '../../utils/validation'; +import { formatProofHexForDisplay, formatPublicSignalsArray } from '../../utils/formatting'; + +/** + * Generates a Groth16 proof using the snarkjs backend: + * fetches WASM + zkey artifacts, runs `groth16.fullProve`, + * then compresses the proof to the 128-byte arkworks canonical format. + */ +export async function runSnarkjsBackend( + circuitType: CircuitType, + inputs: CircuitInputs, + provider: ArtifactProvider, + config: CircuitConfig, + verbose: boolean +): Promise<{ proof: string; publicSignals: string[] }> { + let wasmBinary: Uint8Array | string; + let zkeyBinary: Uint8Array | string; + + try { + if (verbose) console.log('[proof-generator] Fetching circuit artifacts...'); + [wasmBinary, zkeyBinary] = await Promise.all([ + provider.getCircuitWasm(circuitType), + provider.getCircuitZkey(circuitType), + ]); + } catch (error) { + if (verbose) + console.error(`[proof-generator] Failed to load artifacts: ${(error as Error).message}`); + throw new CircuitNotFoundError(circuitType); + } + + if (verbose) console.log('[proof-generator] Step 1: Generating witness + proof with snarkjs...'); + + try { + const { proof, publicSignals } = await snarkjs.groth16.fullProve( + inputs, + wasmBinary, + zkeyBinary + ); + + const compressedProofHex = await compressSnarkjsProofWasm(proof as any); + validateProofSize(compressedProofHex); + + const result = { + proof: compressedProofHex, + publicSignals: formatPublicSignalsArray(publicSignals as string[]), + }; + + if (verbose) { + console.log( + `[proof-generator] Proof generated: ${formatProofHexForDisplay(result.proof, 32)}` + ); + console.log(`[proof-generator] Public signals: ${result.publicSignals.length}`); + } + + return result; + } catch (error) { + throw new ProofGenerationError((error as Error).message); + } +} diff --git a/src/generate/index.ts b/src/generate/index.ts new file mode 100644 index 0000000..14f93c0 --- /dev/null +++ b/src/generate/index.ts @@ -0,0 +1,49 @@ +import { CircuitType, CircuitInputs, ProofResult } from '../circuits/types'; +import { InvalidInputsError, ProofGenerationError } from '../errors'; +import { getCircuitConfig } from '../circuits/config'; +import { validateInputs, validatePublicSignals } from '../utils/validation'; +import { GenerateOptions } from './types'; +import { resolveProvider } from './provider'; +import { runSnarkjsBackend } from './backends/snarkjs'; +import { runArkworksBackend } from './backends/arkworks'; + +export type { GenerateOptions } from './types'; + +export async function generateProof( + circuitType: CircuitType, + inputs: CircuitInputs, + options: GenerateOptions = {} +): Promise { + const { verbose = false, backend = 'snarkjs' } = options; + const provider = resolveProvider(options.provider); + const config = getCircuitConfig(circuitType); + + if (verbose) { + console.log( + `[proof-generator] Generating proof for circuit: ${config.name} (backend: ${backend})` + ); + } + + try { + validateInputs(inputs); + } catch (error) { + throw new InvalidInputsError((error as Error).message); + } + + const proofResult = + backend === 'arkworks' + ? await runArkworksBackend(circuitType, inputs, provider, config, verbose) + : await runSnarkjsBackend(circuitType, inputs, provider, config, verbose); + + try { + validatePublicSignals(proofResult.publicSignals, config.expectedPublicSignals); + } catch (error) { + throw new ProofGenerationError((error as Error).message); + } + + if (verbose) { + console.log('[proof-generator] Proof generation completed successfully.'); + } + + return { proof: proofResult.proof, publicSignals: proofResult.publicSignals, circuitType }; +} diff --git a/src/generate/provider.ts b/src/generate/provider.ts new file mode 100644 index 0000000..c800612 --- /dev/null +++ b/src/generate/provider.ts @@ -0,0 +1,13 @@ +import { ArtifactProvider } from '../providers/interface'; +import { NodeArtifactProvider, WebArtifactProvider } from '../providers'; + +/** + * Returns the caller-supplied provider, or auto-detects Node.js vs browser + * and instantiates the appropriate default provider. + */ +export function resolveProvider(override?: ArtifactProvider): ArtifactProvider { + if (override) return override; + return typeof window !== 'undefined' || typeof self !== 'undefined' + ? new WebArtifactProvider() + : new NodeArtifactProvider(); +} diff --git a/src/generate/types.ts b/src/generate/types.ts new file mode 100644 index 0000000..984a740 --- /dev/null +++ b/src/generate/types.ts @@ -0,0 +1,8 @@ +import type { ArtifactProvider } from '../providers/interface'; + +export interface GenerateOptions { + verbose?: boolean; + provider?: ArtifactProvider; + /** Proof generation backend. Defaults to `'snarkjs'`. */ + backend?: 'snarkjs' | 'arkworks'; +} diff --git a/src/index.ts b/src/index.ts index 5531e4a..41a7de7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,148 +1,39 @@ /** - * Orbinum Proof Generator + * @orbinum/proof-generator — public API barrel. * - * High-performance ZK-SNARK proof generator for Orbinum privacy protocol. - * Combines snarkjs (witness calculation) with arkworks WASM (proof generation) - * to produce 128-byte compressed Groth16 proofs. - * - * @module @orbinum/proof-generator + * All public exports are re-exported from their respective modules. + * No logic lives here. */ -import { - CircuitType, - CircuitInputs, - ProofResult, - CircuitNotFoundError, - ProofGenerationError, - InvalidInputsError, -} from './types'; -import { getCircuitConfig, NodeArtifactProvider, WebArtifactProvider } from './circuits'; -import * as snarkjs from 'snarkjs'; -import { compressSnarkjsProofWasm } from './wasm-loader'; -import { - validateInputs, - validatePublicSignals, - formatProofHexForDisplay, - formatPublicSignalsArray, - validateProofSize, -} from './utils'; -import { ArtifactProvider } from './provider'; - -/** - * Generate a ZK-SNARK proof for an Orbinum circuit - * - * @param circuitType - Type of circuit (Unshield, Transfer, Disclosure, PrivateLink) - * @param inputs - Circuit inputs (structure depends on circuit type) - * @param options - Configuration including artifact provider - */ -export async function generateProof( - circuitType: CircuitType, - inputs: CircuitInputs, - options: { - verbose?: boolean; - provider?: ArtifactProvider; - } = {} -): Promise { - const { verbose = false } = options; - - // Step 0: Determine provider - let provider = options.provider; - - if (!provider) { - if (typeof window !== 'undefined' || typeof self !== 'undefined') { - // Browser environment: Use WebArtifactProvider (Fetch) - provider = new WebArtifactProvider(); - } else { - // Node.js environment: Use NodeArtifactProvider (FS) - provider = new NodeArtifactProvider(); - } - } - - // provider is guaranteed to be defined here - const activeProvider = provider!; - - // Step 1: Get circuit config - const config = getCircuitConfig(circuitType); - - if (verbose) { - console.log(`\n🔐 Generating proof for circuit: ${config.name}`); - } - - // Step 2: Validate inputs - try { - validateInputs(inputs); - } catch (error) { - throw new InvalidInputsError((error as Error).message); - } - - // Step 3: Fetch artifacts via provider - let wasmBinary: Uint8Array | string; - let zkeyBinary: Uint8Array | string; - - try { - if (verbose) console.log(' Fetching circuit artifacts...'); - [wasmBinary, zkeyBinary] = await Promise.all([ - activeProvider.getCircuitWasm(circuitType), - activeProvider.getCircuitZkey(circuitType), - ]); - } catch (error) { - if (verbose) console.error(`Failed to load artifacts: ${(error as Error).message}`); - throw new CircuitNotFoundError(circuitType); - } - - // Step 4: Generate proof with snarkjs - if (verbose) { - console.log('\n📊 Step 1: Generating witness + proof with snarkjs...'); - } - - let proofResult; - try { - // snarkjs fullProve accepts Buffers/Uint8Arrays directly - const { proof, publicSignals } = await snarkjs.groth16.fullProve( - inputs, - wasmBinary, - zkeyBinary - ); - - const compressedProofHex = await compressSnarkjsProofWasm(proof as any); - validateProofSize(compressedProofHex); - - const publicSignalsHex = formatPublicSignalsArray(publicSignals as string[]); - - proofResult = { - proof: compressedProofHex, - publicSignals: publicSignalsHex, - }; - - if (verbose) { - console.log(` ✅ Proof generated: ${formatProofHexForDisplay(proofResult.proof, 32)}`); - console.log(` ✅ Public signals: ${proofResult.publicSignals.length}`); - } - } catch (error) { - throw new ProofGenerationError((error as Error).message); - } +// ── Core API ───────────────────────────────────────────────────────────────── +export { generateProof, type GenerateOptions } from './generate'; +export { generateDisclosureProof } from './disclosure'; - // Step 5: Validate public signals count - try { - validatePublicSignals(proofResult.publicSignals, config.expectedPublicSignals); - } catch (error) { - throw new ProofGenerationError((error as Error).message); - } +// ── Types ───────────────────────────────────────────────────────────────────── +export * from './circuits/types'; +export * from './wasm/types'; +export * from './errors'; +export type { DisclosureMask, DisclosureProofOutput } from './disclosure'; - if (verbose) { - console.log('\n✅ Proof generation completed successfully!\n'); - } +// ── Circuits ────────────────────────────────────────────────────────────────── +export { getCircuitConfig } from './circuits'; - return { - proof: proofResult.proof, - publicSignals: proofResult.publicSignals, - circuitType, - }; -} +// ── Providers ───────────────────────────────────────────────────────────────── +export { NodeArtifactProvider, WebArtifactProvider } from './providers'; +export type { ArtifactProvider, WebProviderOptions } from './providers'; -// Re-export types and utilities for convenience -export * from './types'; -export * from './utils'; -export * from './provider'; -export { NodeArtifactProvider, WebArtifactProvider } from './circuits'; -export { generateDisclosureProof } from './disclosure'; +// ── Utils ───────────────────────────────────────────────────────────────────── +export { validateInputs, validatePublicSignals, validateProofSize } from './utils/validation'; +export { + normalizeProofHex, + formatProofHexForDisplay, + formatPublicSignalsArray, +} from './utils/formatting'; +export { + bigIntToBytes32, + bytes32ToBigInt, + u64ToFieldStr, + hexSignalToBigInt, + bigIntToHex, +} from './utils/encoding'; +export { initWasm, compressSnarkjsProofWasm, generateProofFromWitnessWasm } from './wasm'; diff --git a/src/provider.ts b/src/provider.ts deleted file mode 100644 index 729f6d2..0000000 --- a/src/provider.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { CircuitType } from './types'; - -/** - * Interface for providing circuit artifacts (WASM, zkey) - * allows abstracting file system access for browser compatibility. - */ -export interface ArtifactProvider { - /** - * Get circuit WASM binary - */ - getCircuitWasm(circuitType: CircuitType): Promise; - - /** - * Get circuit zkey binary - */ - getCircuitZkey(circuitType: CircuitType): Promise; -} diff --git a/src/providers/index.ts b/src/providers/index.ts new file mode 100644 index 0000000..a262b33 --- /dev/null +++ b/src/providers/index.ts @@ -0,0 +1,4 @@ +export type { ArtifactProvider } from './interface'; +export { NodeArtifactProvider } from './node'; +export { WebArtifactProvider } from './web'; +export type { WebProviderOptions } from './web'; diff --git a/src/providers/interface.ts b/src/providers/interface.ts new file mode 100644 index 0000000..ee919e7 --- /dev/null +++ b/src/providers/interface.ts @@ -0,0 +1,12 @@ +import { CircuitType } from '../circuits/types'; + +/** + * Interface for providing circuit artifacts (WASM, zkey, ark proving key). + * Abstracts file system access for browser / mobile / Node.js compatibility. + */ +export interface ArtifactProvider { + getCircuitWasm(circuitType: CircuitType): Promise; + getCircuitZkey(circuitType: CircuitType): Promise; + /** Optional: fetch the arkworks compressed proving key (.ark) for the arkworks backend. */ + getCircuitProvingKey?(circuitType: CircuitType): Promise; +} diff --git a/src/providers/node.ts b/src/providers/node.ts new file mode 100644 index 0000000..04e223b --- /dev/null +++ b/src/providers/node.ts @@ -0,0 +1,66 @@ +import { CircuitType } from '../circuits/types'; +import { ArtifactProvider } from './interface'; +import { getCircuitConfig } from '../circuits/config'; + +/** + * Artifact provider for Node.js environments. + * Reads circuit artifacts directly from the `@orbinum/circuits` package + * installed in node_modules via the file system. + */ +export class NodeArtifactProvider implements ArtifactProvider { + // Dynamic require so bundlers do not attempt to polyfill Node.js modules + // when this class is tree-shaken in browser/mobile builds. + private fs: any; + private pathLib: any; + private packageRoot: string; + + constructor(packageRoot?: string) { + try { + this.fs = eval('require')('fs'); + this.pathLib = eval('require')('path'); + } catch { + throw new Error('NodeArtifactProvider requires Node.js environment'); + } + this.packageRoot = packageRoot ?? this.resolvePackageRoot(); + } + + private resolvePackageRoot(): string { + const candidates = ['@orbinum/circuits/package.json', 'orbinum-circuits/package.json']; + for (const candidate of candidates) { + try { + return this.pathLib.dirname(eval('require').resolve(candidate)); + } catch { + continue; + } + } + throw new Error('Cannot resolve @orbinum/circuits package'); + } + + async getCircuitWasm(type: CircuitType): Promise { + const { wasmPath } = getCircuitConfig(type); + return this.fs.readFileSync(this.findArtifactPath(wasmPath)); + } + + async getCircuitZkey(type: CircuitType): Promise { + const { zkeyPath } = getCircuitConfig(type); + return this.fs.readFileSync(this.findArtifactPath(zkeyPath)); + } + + async getCircuitProvingKey(type: CircuitType): Promise { + const { provingKeyPath } = getCircuitConfig(type); + return this.fs.readFileSync(this.findArtifactPath(provingKeyPath)); + } + + private findArtifactPath(filename: string): string { + const searchDirs = [ + this.packageRoot, + this.pathLib.join(this.packageRoot, 'artifacts'), + this.pathLib.join(this.packageRoot, 'pkg'), + ]; + for (const dir of searchDirs) { + const p = this.pathLib.join(dir, filename); + if (this.fs.existsSync(p)) return p; + } + throw new Error(`Artifact ${filename} not found in ${this.packageRoot}`); + } +} diff --git a/src/providers/web.ts b/src/providers/web.ts new file mode 100644 index 0000000..a1249d6 --- /dev/null +++ b/src/providers/web.ts @@ -0,0 +1,205 @@ +import { CircuitType } from '../circuits/types'; +import { ArtifactProvider } from './interface'; + +// ============================================================================ +// Constants +// ============================================================================ + +const UNPKG_BASE = 'https://unpkg.com/@orbinum/circuits'; +const MANIFEST_URL = `${UNPKG_BASE}/manifest.json`; + +// ============================================================================ +// Manifest types +// ============================================================================ + +interface ManifestArtifactEntry { + file: string; + bytes: number; + sha256: string; +} + +interface ManifestCircuitVersion { + version: number; + vk_hash: string; + artifacts: { + wasm: ManifestArtifactEntry; + zkey: ManifestArtifactEntry; + vk_json: ManifestArtifactEntry; + r1cs: ManifestArtifactEntry; + /** Optional arkworks compressed proving key. Present when the manifest includes .ark artifacts. */ + ark?: ManifestArtifactEntry; + }; +} + +interface ManifestCircuit { + active_version: number; + supported_versions: number[]; + versions: Record; +} + +interface CircuitsManifest { + schema_version: string; + package_name: string; + package_version: string; + generated_at: string; + circuits: Record; +} + +// ============================================================================ +// Options +// ============================================================================ + +export type WebProviderOptions = { + /** + * Override the base URL for artifacts and manifest (e.g. self-hosted mirror). + * The provider fetches `{baseUrl}/manifest.json` and resolves artifact + * filenames from it. + */ + baseUrl?: string; + /** + * Pin specific circuits to a version number. + * Use when spending notes created with an older circuit version that differs + * from the current `active_version` in the manifest. + * + * @example { unshield: 1 } // force v1 unshield artifacts + */ + circuitVersions?: Partial>; +}; + +// ============================================================================ +// WebArtifactProvider +// ============================================================================ + +/** + * Artifact provider for browser and mobile environments. + * + * Two modes: + * - **Legacy** (`new WebArtifactProvider('https://...')`) — appends artifact + * filenames directly to the given URL, no manifest fetch. + * - **Manifest** (`new WebArtifactProvider()` or `new WebArtifactProvider({...})`) — + * fetches `manifest.json` from the npm CDN (unpkg), resolves the exact + * artifact filename per circuit version, and pins artifact URLs to the + * `package_version` declared in the manifest. Supports per-circuit version + * overrides for backwards-compatible proof generation. + */ +export class WebArtifactProvider implements ArtifactProvider { + private legacyBaseUrl: string | null = null; + private manifestUrl: string; + private circuitVersions: Partial>; + private manifest: CircuitsManifest | null = null; + private manifestPromise: Promise | null = null; + + constructor(optionsOrUrl?: string | WebProviderOptions) { + if (typeof optionsOrUrl === 'string') { + // Legacy mode: direct URL, no manifest + this.legacyBaseUrl = optionsOrUrl.replace(/\/$/, ''); + this.manifestUrl = ''; + this.circuitVersions = {}; + } else { + const opts = optionsOrUrl ?? {}; + const base = opts.baseUrl?.replace(/\/$/, ''); + this.manifestUrl = base ? `${base}/manifest.json` : MANIFEST_URL; + this.circuitVersions = opts.circuitVersions ?? {}; + } + } + + // --------------------------------------------------------------------------- + // Manifest loading (lazy, cached, single-flight) + // --------------------------------------------------------------------------- + + private async getManifest(): Promise { + if (this.manifest) return this.manifest; + if (!this.manifestPromise) { + this.manifestPromise = fetch(this.manifestUrl) + .then(r => { + if (!r.ok) { + throw new Error(`Failed to fetch circuits manifest: ${this.manifestUrl} (${r.status})`); + } + return r.json() as Promise; + }) + .then(m => { + this.manifest = m; + return m; + }); + } + return this.manifestPromise; + } + + // --------------------------------------------------------------------------- + // Artifact URL resolution via manifest + // --------------------------------------------------------------------------- + + private async resolveArtifactUrl( + circuitType: CircuitType, + artifactType: 'wasm' | 'zkey' | 'ark' + ): Promise { + const manifest = await this.getManifest(); + const circuitName = circuitType as string; + const circuitManifest = manifest.circuits[circuitName]; + + if (!circuitManifest) { + throw new Error(`Circuit "${circuitName}" not found in manifest`); + } + + const requestedVersion = this.circuitVersions[circuitName] ?? circuitManifest.active_version; + + if (!circuitManifest.supported_versions.includes(requestedVersion)) { + throw new Error( + `Circuit "${circuitName}" v${requestedVersion} is no longer supported. ` + + `Supported versions: [${circuitManifest.supported_versions.join(', ')}]` + ); + } + + const versionData = circuitManifest.versions[String(requestedVersion)]; + if (!versionData) { + throw new Error(`Circuit "${circuitName}" v${requestedVersion} not found in manifest`); + } + + const isCustomBase = this.manifestUrl !== MANIFEST_URL; + const artifactBase = isCustomBase + ? this.manifestUrl.replace(/\/manifest\.json$/, '') + : `${UNPKG_BASE}@${manifest.package_version}`; + + if (artifactType === 'ark') { + // Use the manifest entry if present; otherwise derive the filename by convention. + const filename = versionData.artifacts.ark?.file ?? `${circuitName}_pk.ark`; + return `${artifactBase}/${filename}`; + } + + const filename = versionData.artifacts[artifactType].file; + return `${artifactBase}/${filename}`; + } + + // --------------------------------------------------------------------------- + // ArtifactProvider implementation + // --------------------------------------------------------------------------- + + async getCircuitWasm(type: CircuitType): Promise { + if (this.legacyBaseUrl !== null) { + return this.fetchArtifact(`${this.legacyBaseUrl}/${type.toLowerCase()}.wasm`); + } + return this.fetchArtifact(await this.resolveArtifactUrl(type, 'wasm')); + } + + async getCircuitZkey(type: CircuitType): Promise { + if (this.legacyBaseUrl !== null) { + return this.fetchArtifact(`${this.legacyBaseUrl}/${type.toLowerCase()}_pk.zkey`); + } + return this.fetchArtifact(await this.resolveArtifactUrl(type, 'zkey')); + } + + async getCircuitProvingKey(type: CircuitType): Promise { + if (this.legacyBaseUrl !== null) { + return this.fetchArtifact(`${this.legacyBaseUrl}/${type.toLowerCase()}_pk.ark`); + } + return this.fetchArtifact(await this.resolveArtifactUrl(type, 'ark')); + } + + private async fetchArtifact(url: string): Promise { + const response = await fetch(url); + if (!response.ok) { + throw new Error(`Failed to fetch circuit artifact: ${url} (${response.status})`); + } + return new Uint8Array(await response.arrayBuffer()); + } +} diff --git a/src/types.ts b/src/types.ts deleted file mode 100644 index 8f9f808..0000000 --- a/src/types.ts +++ /dev/null @@ -1,123 +0,0 @@ -/** - * Types for Orbinum Proof Generator - */ - -/** Circuit types supported by Orbinum */ -export enum CircuitType { - Unshield = 'unshield', - Transfer = 'transfer', - Disclosure = 'disclosure', - PrivateLink = 'private_link', -} - -/** Circuit input value types (supports nested arrays for 2D inputs) */ -export type CircuitInputValue = string | number | string[] | number[] | string[][] | number[][]; - -/** Circuit input: any key-value pairs (circuit-specific) */ -export type CircuitInputs = Record; - -/** Proof generation result */ -export interface ProofResult { - /** Compressed proof bytes (128 bytes as hex string) */ - proof: string; - /** Public signals (circuit outputs) */ - publicSignals: string[]; - /** Circuit type used */ - circuitType: CircuitType; -} - -/** Circuit configuration */ -export interface CircuitConfig { - /** Circuit name (e.g., 'unshield') */ - name: string; - /** Path to WASM file */ - wasmPath: string; - /** Path to zkey proving key (snarkjs) */ - zkeyPath: string; - /** Path to .ark proving key */ - provingKeyPath: string; - /** Expected number of public signals */ - expectedPublicSignals: number; -} - -/** Witness data (decimal strings from snarkjs) */ -export interface WitnessData { - /** Array of witness elements as decimal strings (snarkjs native format) */ - witness: string[]; -} - -/** Error types */ -export class ProofGeneratorError extends Error { - constructor( - message: string, - public readonly code: string - ) { - super(message); - this.name = 'ProofGeneratorError'; - } -} - -export class WitnessCalculationError extends ProofGeneratorError { - constructor(message: string) { - super(message, 'WITNESS_CALCULATION_FAILED'); - } -} - -export class ProofGenerationError extends ProofGeneratorError { - constructor(message: string) { - super(message, 'PROOF_GENERATION_FAILED'); - } -} - -export class CircuitNotFoundError extends ProofGeneratorError { - constructor(circuitType: CircuitType) { - super(`Circuit not found: ${circuitType}`, 'CIRCUIT_NOT_FOUND'); - } -} - -export class InvalidInputsError extends ProofGeneratorError { - constructor(message: string) { - super(message, 'INVALID_INPUTS'); - } -} - -// ============================================================================ -// Disclosure types -// ============================================================================ - -/** - * Which fields to reveal to the auditor. - * - * At least one of `discloseValue`, `discloseAssetId`, or `discloseOwner` - * must be `true`. - */ -export interface DisclosureMask { - /** Reveal the note value (u64) */ - discloseValue: boolean; - /** Reveal the asset ID (u32) */ - discloseAssetId: boolean; - /** Reveal the owner identity hash (Poseidon(owner_pubkey)) */ - discloseOwner: boolean; -} - -/** Proof output returned by `generateDisclosureProof`. */ -export interface DisclosureProofOutput { - /** 128-byte compressed Groth16 proof as 0x-prefixed hex string */ - proof: string; - /** - * Raw public signals in hex (0x-prefixed, 32 bytes each). - * Order: [commitment, revealed_value, revealed_asset_id, revealed_owner_hash] - */ - publicSignals: string[]; - /** Human-readable revealed data */ - revealedData: { - /** Revealed note value as decimal string, or undefined if not disclosed */ - value?: string; - /** Revealed asset ID as number, or undefined if not disclosed */ - assetId?: number; - /** Revealed owner hash as 0x-prefixed hex, or undefined if not disclosed */ - ownerHash?: string; - /** Note commitment (always present) */ - commitment: string; - }; -} diff --git a/src/utils.ts b/src/utils.ts deleted file mode 100644 index e484b20..0000000 --- a/src/utils.ts +++ /dev/null @@ -1,185 +0,0 @@ -/** - * Utility Functions for Proof Generation - * - * Provides validation and formatting helpers for: - * - Circuit inputs - * - Proof hex strings - * - Public signals - * - BigInt / byte-array conversions - */ - -/** BN254 scalar field modulus */ -const BN254_PRIME = BigInt( - '21888242871839275222246405745257275088696311157297823662689037894645226208583' -); - -// ============================================================================ -// Input Validation -// ============================================================================ - -/** - * Validate circuit inputs structure - * - * Ensures all required fields are present and non-null - */ -export function validateInputs(inputs: Record): void { - if (!inputs || typeof inputs !== 'object') { - throw new Error('Inputs must be an object'); - } - - for (const [key, value] of Object.entries(inputs)) { - if (value === undefined || value === null) { - throw new Error(`Input "${key}" is undefined or null`); - } - } -} - -/** - * Validate public signals count matches expected - */ -export function validatePublicSignals(signals: string[], expected: number): void { - if (signals.length !== expected) { - throw new Error(`Invalid public signals count: expected ${expected}, got ${signals.length}`); - } -} - -/** - * Validate proof size (must be 128 bytes = 256 hex chars) - */ -export function validateProofSize(proofHex: string): void { - const cleanHex = proofHex.startsWith('0x') ? proofHex.slice(2) : proofHex; - - if (cleanHex.length !== 256) { - throw new Error( - `Invalid proof size: expected 256 hex chars (128 bytes), got ${cleanHex.length} chars` - ); - } -} - -// ============================================================================ -// Proof Formatting -// ============================================================================ - -/** - * Normalize proof hex string (ensure 0x prefix, lowercase) - * - * @example - * normalizeProofHex("ABCD...") // "0xabcd..." - * normalizeProofHex("0xABCD...") // "0xabcd..." - */ -export function normalizeProofHex(proofHex: string): string { - const withPrefix = proofHex.startsWith('0x') ? proofHex : '0x' + proofHex; - return withPrefix.toLowerCase(); -} - -/** - * Format proof hex for display (truncated) - * - * @param proofHex - Full proof hex string - * @param maxLength - Maximum length for display (default: 32) - * @returns Truncated hex string - * - * @example - * formatProofHexForDisplay("0xabcd...1234", 20) // "0xabcd...1234" - */ -export function formatProofHexForDisplay(proofHex: string, maxLength: number = 32): string { - if (proofHex.length <= maxLength) { - return proofHex; - } - - const halfLen = maxLength / 2; - const start = proofHex.slice(0, halfLen); - const end = proofHex.slice(-halfLen); - return `${start}...${end}`; -} - -/** - * Format array of public signals to hex strings - * - * @param signals - Array of signal values (decimal strings, hex, or BigInt) - * @returns Array of 32-byte hex strings - */ -export function formatPublicSignalsArray(signals: (bigint | number | string)[]): string[] { - return signals.map(value => { - let bigIntValue: bigint; - - if (typeof value === 'string') { - bigIntValue = value.startsWith('0x') ? BigInt(value) : BigInt(value); - } else if (typeof value === 'bigint') { - bigIntValue = value; - } else { - bigIntValue = BigInt(value); - } - - // Validate within BN254 field - if (bigIntValue < BigInt(0) || bigIntValue >= BN254_PRIME) { - throw new Error(`Value out of BN254 field range: ${bigIntValue.toString()}`); - } - - // Convert to 32-byte hex (little-endian) - const hex = bigIntValue.toString(16).padStart(64, '0'); - - // Reverse bytes for little-endian - const bytes: string[] = []; - for (let i = hex.length - 2; i >= 0; i -= 2) { - bytes.push(hex.substr(i, 2)); - } - - return '0x' + bytes.join(''); - }); -} - -// ============================================================================ -// BigInt / byte-array conversions -// ============================================================================ - -/** - * Convert a BigInt to a 32-byte Uint8Array (big-endian). - */ -export function bigIntToBytes32(n: bigint): Uint8Array { - const buf = new Uint8Array(32); - let remaining = n; - for (let i = 31; i >= 0; i--) { - buf[i] = Number(remaining & 0xffn); - remaining >>= 8n; - } - return buf; -} - -/** - * Convert a 32-byte Uint8Array (big-endian) to a BigInt. - */ -export function bytes32ToBigInt(buf: Uint8Array): bigint { - let result = 0n; - for (let i = 0; i < 32; i++) { - result = (result << 8n) | BigInt(buf[i]); - } - return result; -} - -/** - * Encode a u64 value as a BN254 field element decimal string for snarkjs. - */ -export function u64ToFieldStr(value: bigint): string { - return value.toString(10); -} - -/** - * Parse a little-endian hex public signal (0x-prefixed, 32 bytes) back to BigInt. - * - * Public signals returned by the proof generator are little-endian; this - * function reverses the bytes before interpreting as a field element. - */ -export function hexSignalToBigInt(hex: string): bigint { - const clean = hex.startsWith('0x') || hex.startsWith('0X') ? hex.slice(2) : hex; - const buf = Buffer.from(clean.padStart(64, '0'), 'hex'); - const reversed = Buffer.from(buf).reverse(); - return bytes32ToBigInt(new Uint8Array(reversed)); -} - -/** - * Convert a BigInt to a 0x-prefixed 64-hex-char big-endian string. - */ -export function bigIntToHex(n: bigint): string { - return '0x' + n.toString(16).padStart(64, '0'); -} diff --git a/src/utils/encoding.ts b/src/utils/encoding.ts new file mode 100644 index 0000000..702a898 --- /dev/null +++ b/src/utils/encoding.ts @@ -0,0 +1,54 @@ +/** + * BigInt ↔ byte-array ↔ hex encoding helpers. + * + * All functions that convert between BigInt values and binary representations + * used by snarkjs, Poseidon, and the chain extrinsics live here. + */ + +/** Convert a BigInt to a 32-byte Uint8Array (big-endian). */ +export function bigIntToBytes32(n: bigint): Uint8Array { + const buf = new Uint8Array(32); + let remaining = n; + for (let i = 31; i >= 0; i--) { + buf[i] = Number(remaining & 0xffn); + remaining >>= 8n; + } + return buf; +} + +/** Convert a 32-byte big-endian Uint8Array to a BigInt. */ +export function bytes32ToBigInt(buf: Uint8Array): bigint { + let result = 0n; + for (let i = 0; i < 32; i++) { + result = (result << 8n) | BigInt(buf[i]); + } + return result; +} + +/** Encode a u64 value as a BN254 field element decimal string for snarkjs. */ +export function u64ToFieldStr(value: bigint): string { + return value.toString(10); +} + +/** + * Parse a little-endian hex public signal (0x-prefixed, 32 bytes) back to BigInt. + * + * Public signals returned by the proof generator are little-endian; this + * function reverses the bytes before interpreting as a field element. + */ +export function hexSignalToBigInt(hex: string): bigint { + const clean = hex.startsWith('0x') || hex.startsWith('0X') ? hex.slice(2) : hex; + const padded = clean.padStart(64, '0'); + const bytes = new Uint8Array(32); + for (let i = 0; i < 32; i++) { + bytes[i] = parseInt(padded.slice(i * 2, i * 2 + 2), 16); + } + // reverse bytes (little-endian → big-endian) then interpret as BigInt + bytes.reverse(); + return bytes32ToBigInt(bytes); +} + +/** Convert a BigInt to a 0x-prefixed 64-hex-char big-endian string. */ +export function bigIntToHex(n: bigint): string { + return '0x' + n.toString(16).padStart(64, '0'); +} diff --git a/src/utils/formatting.ts b/src/utils/formatting.ts new file mode 100644 index 0000000..6193c51 --- /dev/null +++ b/src/utils/formatting.ts @@ -0,0 +1,41 @@ +/** + * Proof and public signal formatting functions. + */ + +/** BN254 scalar field modulus */ +const BN254_PRIME = BigInt( + '21888242871839275222246405745257275088696311157297823662689037894645226208583' +); + +export function normalizeProofHex(proofHex: string): string { + const withPrefix = proofHex.startsWith('0x') ? proofHex : '0x' + proofHex; + return withPrefix.toLowerCase(); +} + +export function formatProofHexForDisplay(proofHex: string, maxLength: number = 32): string { + if (proofHex.length <= maxLength) return proofHex; + const halfLen = maxLength / 2; + return `${proofHex.slice(0, halfLen)}...${proofHex.slice(-halfLen)}`; +} + +/** + * Converts an array of snarkjs public signals (decimal strings) to + * 0x-prefixed 32-byte little-endian hex strings for use in extrinsics. + */ +export function formatPublicSignalsArray(signals: (bigint | number | string)[]): string[] { + return signals.map(value => { + const bigIntValue: bigint = + typeof value === 'string' ? BigInt(value) : typeof value === 'bigint' ? value : BigInt(value); + + if (bigIntValue < 0n || bigIntValue >= BN254_PRIME) { + throw new Error(`Value out of BN254 field range: ${bigIntValue.toString()}`); + } + + const hex = bigIntValue.toString(16).padStart(64, '0'); + const bytes: string[] = []; + for (let i = hex.length - 2; i >= 0; i -= 2) { + bytes.push(hex.substr(i, 2)); + } + return '0x' + bytes.join(''); + }); +} diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 0000000..a394973 --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1,13 @@ +export { validateInputs, validatePublicSignals, validateProofSize } from './validation'; +export { + normalizeProofHex, + formatProofHexForDisplay, + formatPublicSignalsArray, +} from './formatting'; +export { + bigIntToBytes32, + bytes32ToBigInt, + u64ToFieldStr, + hexSignalToBigInt, + bigIntToHex, +} from './encoding'; diff --git a/src/utils/validation.ts b/src/utils/validation.ts new file mode 100644 index 0000000..a1736f9 --- /dev/null +++ b/src/utils/validation.ts @@ -0,0 +1,29 @@ +/** + * Circuit input and proof validation functions. + */ + +export function validateInputs(inputs: Record): void { + if (!inputs || typeof inputs !== 'object') { + throw new Error('Inputs must be an object'); + } + for (const [key, value] of Object.entries(inputs)) { + if (value === undefined || value === null) { + throw new Error(`Input "${key}" is undefined or null`); + } + } +} + +export function validatePublicSignals(signals: string[], expected: number): void { + if (signals.length !== expected) { + throw new Error(`Invalid public signals count: expected ${expected}, got ${signals.length}`); + } +} + +export function validateProofSize(proofHex: string): void { + const cleanHex = proofHex.startsWith('0x') ? proofHex.slice(2) : proofHex; + if (cleanHex.length !== 256) { + throw new Error( + `Invalid proof size: expected 256 hex chars (128 bytes), got ${cleanHex.length} chars` + ); + } +} diff --git a/src/wasm-loader.ts b/src/wasm-loader.ts deleted file mode 100644 index efd4784..0000000 --- a/src/wasm-loader.ts +++ /dev/null @@ -1,91 +0,0 @@ -/** - * WASM loader for universal (Node.js + Browser) environments - * - * Provides a unified interface for proof generation using arkworks WASM module. - * Works identically in Node.js, browsers, Electron, and Tauri. - * - * Uses @orbinum/groth16-proofs package from npm. - */ - -interface SnarkjsProofLike { - pi_a: Array; - pi_b: Array>; - pi_c: Array; -} - -let wasmModule: any = null; - -/** - * Initialize WASM module (idempotent - safe to call multiple times) - */ -export async function initWasm(): Promise { - if (wasmModule) { - return; // Already initialized - } - - try { - // Import @orbinum/groth16-proofs from npm - const wasm = await import('@orbinum/groth16-proofs'); - - // Initialize WASM - // For Node.js: Load manually from node_modules - if (typeof process !== 'undefined' && process.versions && process.versions.node) { - const fs = await import('fs'); - const path = await import('path'); - - // Resolve path to WASM file in node_modules - const wasmModulePath = require.resolve('@orbinum/groth16-proofs'); - const wasmDir = path.dirname(wasmModulePath); - const wasmPath = path.join(wasmDir, 'groth16_proofs_bg.wasm'); - - const wasmBuffer = fs.readFileSync(wasmPath); - - if (typeof wasm.initSync === 'function') { - wasm.initSync({ module: wasmBuffer }); - } else if (typeof wasm.default === 'function') { - await wasm.default({ module: wasmBuffer }); - } - } else { - // For browsers: Use default() which handles fetch automatically - if (typeof wasm.default === 'function') { - await wasm.default(); - } - } - - // Initialize panic hook for better error messages - if (typeof wasm.init_panic_hook === 'function') { - wasm.init_panic_hook(); - } - - wasmModule = wasm; - } catch (error) { - throw new Error(`Failed to initialize WASM module: ${(error as Error).message}`); - } -} - -/** - * Compress a snarkjs Groth16 proof to arkworks canonical compressed format (128 bytes) - * - * @param proof - snarkjs proof object with pi_a/pi_b/pi_c - * @returns 0x-prefixed 128-byte compressed proof hex - */ -export async function compressSnarkjsProofWasm(proof: SnarkjsProofLike): Promise { - if (!wasmModule) { - await initWasm(); - } - - try { - const normalizedProof = { - pi_a: [String(proof.pi_a[0]), String(proof.pi_a[1])], - pi_b: [ - [String(proof.pi_b[0][0]), String(proof.pi_b[0][1])], - [String(proof.pi_b[1][0]), String(proof.pi_b[1][1])], - ], - pi_c: [String(proof.pi_c[0]), String(proof.pi_c[1])], - }; - - return wasmModule.compress_snarkjs_proof_wasm(JSON.stringify(normalizedProof)); - } catch (error) { - throw new Error(`WASM proof compression failed: ${(error as Error).message}`); - } -} diff --git a/src/wasm/index.ts b/src/wasm/index.ts new file mode 100644 index 0000000..6247b0b --- /dev/null +++ b/src/wasm/index.ts @@ -0,0 +1 @@ +export { initWasm, compressSnarkjsProofWasm, generateProofFromWitnessWasm } from './loader'; diff --git a/src/wasm/loader.ts b/src/wasm/loader.ts new file mode 100644 index 0000000..3aa2e07 --- /dev/null +++ b/src/wasm/loader.ts @@ -0,0 +1,146 @@ +/** + * WASM loader for universal (Node.js + Browser) environments. + * + * Initializes the `@orbinum/groth16-proofs` WASM module and exposes + * `compressSnarkjsProofWasm`, which converts a snarkjs Groth16 proof + * (pi_a / pi_b / pi_c) to the 128-byte arkworks canonical compressed format + * accepted by `pallet-zk-verifier` on-chain. + */ + +// Read the installed version at build time so the CDN URL stays in sync. +// resolveJsonModule must be enabled in tsconfig (it is). +import groth16pkg from '@orbinum/groth16-proofs/package.json'; + +interface SnarkjsProofLike { + pi_a: Array; + pi_b: Array>; + pi_c: Array; +} + +// CDN URL pattern for the WASM binary. +// `groth16pkg.version` is resolved at build time from the installed package.json, +// so this stays in sync automatically whenever the dependency is upgraded. +const GROTH16_WASM_CDN = `https://unpkg.com/@orbinum/groth16-proofs@${groth16pkg.version}/groth16_proofs_bg.wasm`; + +let wasmModule: any = null; + +/** Initialize the WASM module. Idempotent — safe to call multiple times. */ +export async function initWasm(): Promise { + if (wasmModule) return; + + try { + const wasm = await import('@orbinum/groth16-proofs'); + + if (typeof window === 'undefined' && typeof self === 'undefined') { + // Node.js: load the WASM binary from disk via dynamic require. + const requireFn = eval('require'); + const fs = requireFn('fs'); + const path = requireFn('path'); + const wasmDir = path.dirname(requireFn.resolve('@orbinum/groth16-proofs')); + const wasmBuffer = fs.readFileSync(path.join(wasmDir, 'groth16_proofs_bg.wasm')); + + if (typeof wasm.initSync === 'function') { + wasm.initSync({ module: wasmBuffer }); + } else if (typeof wasm.default === 'function') { + await wasm.default({ module: wasmBuffer }); + } + } else { + // Browser: pass the WASM CDN URL directly to the init function. + // + // Relying on `new URL('groth16_proofs_bg.wasm', import.meta.url)` (the + // wasm-pack default) breaks in Vite dev mode because the bundler moves the + // JS out of its original node_modules path while the .wasm binary stays + // behind, producing a 404. Loading from CDN is the same strategy already + // used for @orbinum/circuits artifacts and avoids all import.meta.url / + // Vite asset-serving issues entirely. + // + // TypeScript (module: "CommonJS") compiles dynamic import() to + // __importStar(require()), which causes Vite's CJS→ESM interop to wrap the + // namespace and reassign `wasm.default` to the namespace object. Resolve the + // actual __wbg_init function defensively (direct ESM or CJS-interop path). + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const defaultExport = (wasm as any).default; + const initFn: ((url: string) => Promise) | undefined = + typeof defaultExport === 'function' + ? defaultExport + : typeof defaultExport?.default === 'function' + ? defaultExport.default + : undefined; + + if (initFn) { + await initFn(GROTH16_WASM_CDN); + } + } + + if (typeof wasm.init_panic_hook === 'function') { + try { + wasm.init_panic_hook(); + } catch { + // init_panic_hook is a developer-aid only; safe to swallow. + } + } + + wasmModule = wasm; + } catch (error) { + throw new Error(`Failed to initialize WASM module: ${(error as Error).message}`); + } +} + +/** + * Compress a snarkjs Groth16 proof to the arkworks canonical compressed + * format (128 bytes, 0x-prefixed hex). + */ +export async function compressSnarkjsProofWasm(proof: SnarkjsProofLike): Promise { + if (!wasmModule) await initWasm(); + + const normalizedProof = { + pi_a: [String(proof.pi_a[0]), String(proof.pi_a[1])], + pi_b: [ + [String(proof.pi_b[0][0]), String(proof.pi_b[0][1])], + [String(proof.pi_b[1][0]), String(proof.pi_b[1][1])], + ], + pi_c: [String(proof.pi_c[0]), String(proof.pi_c[1])], + }; + + try { + return wasmModule.compress_snarkjs_proof_wasm(JSON.stringify(normalizedProof)); + } catch (error) { + throw new Error(`WASM proof compression failed: ${(error as Error).message}`); + } +} + +/** + * Generate a Groth16 proof entirely within arkworks using a pre-computed + * witness (decimal string array) and an `.ark` compressed proving key. + * + * @param numPublicSignals - Number of public signals to extract from the witness. + * @param witnessDecimalJson - JSON array of witness values as decimal strings, + * e.g. `["1","12345","67890"]` (snarkjs native format). + * @param provingKeyBytes - Serialized arkworks compressed proving key (.ark file). + * @returns Object with `proof` (0x-prefixed 128-byte hex) and `publicSignals` + * (array of 0x-prefixed 32-byte little-endian hex strings). + */ +export async function generateProofFromWitnessWasm( + numPublicSignals: number, + witnessDecimalJson: string, + provingKeyBytes: Uint8Array +): Promise<{ proof: string; publicSignals: string[] }> { + if (!wasmModule) await initWasm(); + + let raw: string; + try { + raw = wasmModule.generate_proof_from_decimal_wasm( + numPublicSignals, + witnessDecimalJson, + provingKeyBytes + ); + } catch (error) { + throw new Error(`WASM proof generation failed: ${(error as Error).message}`); + } + + try { + return JSON.parse(raw) as { proof: string; publicSignals: string[] }; + } catch (error) { + throw new Error(`Failed to parse WASM proof output: ${(error as Error).message}`); + } +} diff --git a/src/wasm/types.ts b/src/wasm/types.ts new file mode 100644 index 0000000..9e741a6 --- /dev/null +++ b/src/wasm/types.ts @@ -0,0 +1,5 @@ +/** Witness data (decimal strings from snarkjs) */ +export interface WitnessData { + /** Array of witness elements as decimal strings (snarkjs native format) */ + witness: string[]; +} diff --git a/tests/circuits/config.test.ts b/tests/circuits/config.test.ts new file mode 100644 index 0000000..c62d57b --- /dev/null +++ b/tests/circuits/config.test.ts @@ -0,0 +1,73 @@ +import { describe, it, expect } from 'vitest'; +import { getCircuitConfig } from '../../src/circuits/config'; +import { CircuitType } from '../../src/circuits/types'; + +describe('getCircuitConfig', () => { + it('returns correct config for Unshield', () => { + const config = getCircuitConfig(CircuitType.Unshield); + expect(config.name).toBe('unshield'); + expect(config.wasmPath).toBe('unshield.wasm'); + expect(config.zkeyPath).toBe('unshield_pk.zkey'); + expect(config.provingKeyPath).toBe('unshield_pk.ark'); + expect(config.expectedPublicSignals).toBe(5); + }); + + it('returns correct config for Transfer', () => { + const config = getCircuitConfig(CircuitType.Transfer); + expect(config.name).toBe('transfer'); + expect(config.wasmPath).toBe('transfer.wasm'); + expect(config.zkeyPath).toBe('transfer_pk.zkey'); + expect(config.provingKeyPath).toBe('transfer_pk.ark'); + expect(config.expectedPublicSignals).toBe(5); + }); + + it('returns correct config for Disclosure', () => { + const config = getCircuitConfig(CircuitType.Disclosure); + expect(config.name).toBe('disclosure'); + expect(config.wasmPath).toBe('disclosure.wasm'); + expect(config.zkeyPath).toBe('disclosure_pk.zkey'); + expect(config.provingKeyPath).toBe('disclosure_pk.ark'); + expect(config.expectedPublicSignals).toBe(4); + }); + + it('returns correct config for PrivateLink', () => { + const config = getCircuitConfig(CircuitType.PrivateLink); + expect(config.name).toBe('private_link'); + expect(config.wasmPath).toBe('private_link.wasm'); + expect(config.zkeyPath).toBe('private_link_pk.zkey'); + expect(config.provingKeyPath).toBe('private_link_pk.ark'); + expect(config.expectedPublicSignals).toBe(2); + }); + + it('all configs have name, wasmPath, zkeyPath, provingKeyPath, expectedPublicSignals', () => { + const types = [ + CircuitType.Unshield, + CircuitType.Transfer, + CircuitType.Disclosure, + CircuitType.PrivateLink, + ]; + for (const type of types) { + const config = getCircuitConfig(type); + expect(config.name).toBeTruthy(); + expect(config.wasmPath).toMatch(/\.wasm$/); + expect(config.zkeyPath).toMatch(/\.zkey$/); + expect(config.provingKeyPath).toMatch(/\.ark$/); + expect(config.expectedPublicSignals).toBeGreaterThan(0); + } + }); + + it('wasmPath matches name.wasm pattern', () => { + const config = getCircuitConfig(CircuitType.Unshield); + expect(config.wasmPath).toBe(`${config.name}.wasm`); + }); + + it('zkeyPath matches name_pk.zkey pattern', () => { + const config = getCircuitConfig(CircuitType.Unshield); + expect(config.zkeyPath).toBe(`${config.name}_pk.zkey`); + }); + + it('provingKeyPath matches name_pk.ark pattern', () => { + const config = getCircuitConfig(CircuitType.Unshield); + expect(config.provingKeyPath).toBe(`${config.name}_pk.ark`); + }); +}); diff --git a/tests/disclosure/index.test.ts b/tests/disclosure/index.test.ts new file mode 100644 index 0000000..35e9cd4 --- /dev/null +++ b/tests/disclosure/index.test.ts @@ -0,0 +1,199 @@ +/** + * Tests: disclosure/index.ts — generateDisclosureProof() + * + * generateProof and circomlibjs are mocked so no real circuit artifacts + * or cryptographic operations are required. + */ + +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { generateDisclosureProof } from '../../src/disclosure'; +import type { DisclosureMask } from '../../src/disclosure'; +import type { ArtifactProvider } from '../../src/providers/interface'; + +// ─── Mock circomlibjs ───────────────────────────────────────────────────────── + +vi.mock('circomlibjs', () => { + const poseidon = Object.assign(vi.fn().mockReturnValue('stub'), { + F: { toObject: vi.fn().mockReturnValue(999n) }, + }); + return { + buildPoseidon: vi.fn().mockResolvedValue(poseidon), + }; +}); + +// ─── Mock generateProof ─────────────────────────────────────────────────────── + +vi.mock('../../src/generate', () => ({ + generateProof: vi.fn().mockResolvedValue({ + proof: '0x' + 'aa'.repeat(128), + publicSignals: [ + // commitment, revealed_value, revealed_asset_id, revealed_owner_hash + '0x' + '01'.repeat(32), + '0x' + '02'.repeat(32), + '0x' + '03'.repeat(32), + '0x' + '04'.repeat(32), + ], + circuitType: 'disclosure', + }), +})); + +// ─── Helpers ────────────────────────────────────────────────────────────────── + +const VALUE = 1000n; +const OWNER_PUBKEY = 12345n; +const BLINDING = 999n; +const ASSET_ID = 1n; +const COMMITMENT = 42n; + +const MASK_ALL: DisclosureMask = { + discloseValue: true, + discloseAssetId: true, + discloseOwner: true, +}; + +const MOCK_PROVIDER: ArtifactProvider = { + getCircuitWasm: vi.fn(), + getCircuitZkey: vi.fn(), +}; + +// ─── Tests ──────────────────────────────────────────────────────────────────── + +describe('generateDisclosureProof', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('returns proof, publicSignals and revealedData', async () => { + const result = await generateDisclosureProof( + VALUE, + OWNER_PUBKEY, + BLINDING, + ASSET_ID, + COMMITMENT, + MASK_ALL, + { provider: MOCK_PROVIDER } + ); + expect(result.proof).toBe('0x' + 'aa'.repeat(128)); + expect(result.publicSignals).toHaveLength(4); + expect(result.revealedData.commitment).toBeDefined(); + }); + + it('populates revealedData.value when discloseValue is true', async () => { + const result = await generateDisclosureProof( + VALUE, + OWNER_PUBKEY, + BLINDING, + ASSET_ID, + COMMITMENT, + MASK_ALL, + { provider: MOCK_PROVIDER } + ); + expect(result.revealedData.value).toBeDefined(); + expect(typeof result.revealedData.value).toBe('string'); + }); + + it('populates revealedData.assetId when discloseAssetId is true', async () => { + const result = await generateDisclosureProof( + VALUE, + OWNER_PUBKEY, + BLINDING, + ASSET_ID, + COMMITMENT, + MASK_ALL, + { provider: MOCK_PROVIDER } + ); + expect(result.revealedData.assetId).toBeDefined(); + expect(typeof result.revealedData.assetId).toBe('number'); + }); + + it('populates revealedData.ownerHash when discloseOwner is true', async () => { + const result = await generateDisclosureProof( + VALUE, + OWNER_PUBKEY, + BLINDING, + ASSET_ID, + COMMITMENT, + MASK_ALL, + { provider: MOCK_PROVIDER } + ); + expect(result.revealedData.ownerHash).toBeDefined(); + expect(result.revealedData.ownerHash).toMatch(/^0x/); + }); + + it('omits revealedData.value when discloseValue is false', async () => { + const mask: DisclosureMask = { + discloseValue: false, + discloseAssetId: true, + discloseOwner: false, + }; + const result = await generateDisclosureProof( + VALUE, + OWNER_PUBKEY, + BLINDING, + ASSET_ID, + COMMITMENT, + mask, + { provider: MOCK_PROVIDER } + ); + expect(result.revealedData.value).toBeUndefined(); + }); + + it('omits revealedData.assetId when discloseAssetId is false', async () => { + const mask: DisclosureMask = { + discloseValue: true, + discloseAssetId: false, + discloseOwner: false, + }; + const result = await generateDisclosureProof( + VALUE, + OWNER_PUBKEY, + BLINDING, + ASSET_ID, + COMMITMENT, + mask, + { provider: MOCK_PROVIDER } + ); + expect(result.revealedData.assetId).toBeUndefined(); + }); + + it('omits revealedData.ownerHash when discloseOwner is false', async () => { + const mask: DisclosureMask = { + discloseValue: true, + discloseAssetId: false, + discloseOwner: false, + }; + const result = await generateDisclosureProof( + VALUE, + OWNER_PUBKEY, + BLINDING, + ASSET_ID, + COMMITMENT, + mask, + { provider: MOCK_PROVIDER } + ); + expect(result.revealedData.ownerHash).toBeUndefined(); + }); + + it('throws when all mask fields are false', async () => { + const emptyMask: DisclosureMask = { + discloseValue: false, + discloseAssetId: false, + discloseOwner: false, + }; + await expect( + generateDisclosureProof(VALUE, OWNER_PUBKEY, BLINDING, ASSET_ID, COMMITMENT, emptyMask) + ).rejects.toThrow('DisclosureMask'); + }); + + it('passes the provider option through to generateProof', async () => { + const { generateProof } = await import('../../src/generate'); + await generateDisclosureProof(VALUE, OWNER_PUBKEY, BLINDING, ASSET_ID, COMMITMENT, MASK_ALL, { + provider: MOCK_PROVIDER, + }); + expect(generateProof).toHaveBeenCalledWith( + 'disclosure', + expect.any(Object), + expect.objectContaining({ provider: MOCK_PROVIDER }) + ); + }); +}); diff --git a/tests/errors/index.test.ts b/tests/errors/index.test.ts new file mode 100644 index 0000000..e7f797f --- /dev/null +++ b/tests/errors/index.test.ts @@ -0,0 +1,84 @@ +/** + * Tests: errors/index.ts + * + * Verifies that each error class carries the correct name, message, + * error code, and inheritance chain. + */ + +import { describe, it, expect } from 'vitest'; +import { + ProofGeneratorError, + WitnessCalculationError, + ProofGenerationError, + CircuitNotFoundError, + InvalidInputsError, +} from '../../src/errors'; +import { CircuitType } from '../../src/circuits/types'; + +describe('ProofGeneratorError', () => { + it('sets message, code and name', () => { + const err = new ProofGeneratorError('something went wrong', 'SOME_CODE'); + expect(err.message).toBe('something went wrong'); + expect(err.code).toBe('SOME_CODE'); + expect(err.name).toBe('ProofGeneratorError'); + }); + + it('is an instance of Error', () => { + expect(new ProofGeneratorError('msg', 'CODE')).toBeInstanceOf(Error); + }); +}); + +describe('WitnessCalculationError', () => { + it('sets code to WITNESS_CALCULATION_FAILED', () => { + const err = new WitnessCalculationError('bad witness'); + expect(err.code).toBe('WITNESS_CALCULATION_FAILED'); + expect(err.message).toBe('bad witness'); + }); + + it('extends ProofGeneratorError', () => { + expect(new WitnessCalculationError('msg')).toBeInstanceOf(ProofGeneratorError); + }); +}); + +describe('ProofGenerationError', () => { + it('sets code to PROOF_GENERATION_FAILED', () => { + const err = new ProofGenerationError('proving failed'); + expect(err.code).toBe('PROOF_GENERATION_FAILED'); + expect(err.message).toBe('proving failed'); + }); + + it('extends ProofGeneratorError', () => { + expect(new ProofGenerationError('msg')).toBeInstanceOf(ProofGeneratorError); + }); +}); + +describe('CircuitNotFoundError', () => { + it('builds message from CircuitType', () => { + const err = new CircuitNotFoundError(CircuitType.Unshield); + expect(err.message).toBe('Circuit not found: unshield'); + expect(err.code).toBe('CIRCUIT_NOT_FOUND'); + }); + + it('works for every CircuitType variant', () => { + for (const ct of Object.values(CircuitType)) { + const err = new CircuitNotFoundError(ct); + expect(err.message).toContain(ct); + } + }); + + it('extends ProofGeneratorError', () => { + expect(new CircuitNotFoundError(CircuitType.Transfer)).toBeInstanceOf(ProofGeneratorError); + }); +}); + +describe('InvalidInputsError', () => { + it('sets code to INVALID_INPUTS', () => { + const err = new InvalidInputsError('missing field'); + expect(err.code).toBe('INVALID_INPUTS'); + expect(err.message).toBe('missing field'); + }); + + it('extends ProofGeneratorError', () => { + expect(new InvalidInputsError('msg')).toBeInstanceOf(ProofGeneratorError); + }); +}); diff --git a/tests/generate/index.test.ts b/tests/generate/index.test.ts new file mode 100644 index 0000000..115c768 --- /dev/null +++ b/tests/generate/index.test.ts @@ -0,0 +1,237 @@ +/** + * Tests: generateProof — backend option ('snarkjs' | 'arkworks') + * + * Both backends are exercised with a minimal stub provider and mocked + * snarkjs / WASM modules so no real circuit artifacts are required. + */ + +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { generateProof } from '../../src/generate'; +import { CircuitType } from '../../src/circuits/types'; +import { CircuitNotFoundError, ProofGenerationError, InvalidInputsError } from '../../src/errors'; +import type { ArtifactProvider } from '../../src/providers/interface'; + +// ─── Mock @orbinum/groth16-proofs ───────────────────────────────────────────── + +vi.mock('@orbinum/groth16-proofs', () => ({ + default: vi.fn().mockResolvedValue(undefined), + init_panic_hook: vi.fn(), + compress_snarkjs_proof_wasm: vi.fn().mockReturnValue('0x' + 'ab'.repeat(128)), + generate_proof_from_decimal_wasm: vi.fn().mockReturnValue( + JSON.stringify({ + proof: '0x' + 'cd'.repeat(128), + publicSignals: [ + '0x' + '01'.repeat(32), + '0x' + '02'.repeat(32), + '0x' + '03'.repeat(32), + '0x' + '04'.repeat(32), + ], + }) + ), + initSync: vi.fn(), +})); + +// ─── Mock snarkjs ───────────────────────────────────────────────────────────── + +vi.mock('snarkjs', () => ({ + groth16: { + fullProve: vi.fn().mockResolvedValue({ + proof: { + pi_a: ['1', '2', '1'], + pi_b: [ + ['3', '4'], + ['5', '6'], + ['1', '0'], + ], + pi_c: ['7', '8', '1'], + }, + publicSignals: ['10', '20', '30', '40'], + }), + }, + wtns: { + calculate: vi.fn().mockResolvedValue(undefined), + exportJson: vi.fn().mockResolvedValue([1n, 10n, 20n, 30n, 40n]), + }, +})); + +// ─── Helpers ────────────────────────────────────────────────────────────────── + +const FAKE_WASM = new Uint8Array([1, 2, 3]); +const FAKE_ZKEY = new Uint8Array([4, 5, 6]); +const FAKE_ARK = new Uint8Array([7, 8, 9]); + +const VALID_INPUTS = { commitment: '12345', nullifier: '67890' }; + +function makeSnarkjsProvider(): ArtifactProvider { + return { + getCircuitWasm: vi.fn().mockResolvedValue(FAKE_WASM), + getCircuitZkey: vi.fn().mockResolvedValue(FAKE_ZKEY), + }; +} + +function makeArkworksProvider(): ArtifactProvider { + return { + getCircuitWasm: vi.fn().mockResolvedValue(FAKE_WASM), + getCircuitZkey: vi.fn().mockResolvedValue(FAKE_ZKEY), + getCircuitProvingKey: vi.fn().mockResolvedValue(FAKE_ARK), + }; +} + +// ─── snarkjs backend (default) ─────────────────────────────────────────────── + +describe('generateProof — snarkjs backend (default)', () => { + let provider: ArtifactProvider; + + beforeEach(() => { + vi.clearAllMocks(); + provider = makeSnarkjsProvider(); + }); + + it('returns ProofResult with proof and publicSignals', async () => { + const result = await generateProof(CircuitType.Disclosure, VALID_INPUTS, { provider }); + expect(result.proof).toMatch(/^0x[0-9a-f]+$/i); + expect(result.publicSignals).toHaveLength(4); + expect(result.circuitType).toBe(CircuitType.Disclosure); + }); + + it('uses snarkjs backend by default (no backend option)', async () => { + const snarkjs = await import('snarkjs'); + await generateProof(CircuitType.Disclosure, VALID_INPUTS, { provider }); + expect(snarkjs.groth16.fullProve).toHaveBeenCalledTimes(1); + }); + + it('explicit backend: snarkjs also uses snarkjs', async () => { + const snarkjs = await import('snarkjs'); + await generateProof(CircuitType.Disclosure, VALID_INPUTS, { provider, backend: 'snarkjs' }); + expect(snarkjs.groth16.fullProve).toHaveBeenCalledTimes(1); + }); + + it('fetches WASM and zkey from provider', async () => { + await generateProof(CircuitType.Disclosure, VALID_INPUTS, { provider }); + expect(provider.getCircuitWasm).toHaveBeenCalledWith(CircuitType.Disclosure); + expect(provider.getCircuitZkey).toHaveBeenCalledWith(CircuitType.Disclosure); + }); + + it('throws CircuitNotFoundError when provider rejects', async () => { + const badProvider: ArtifactProvider = { + getCircuitWasm: vi.fn().mockRejectedValue(new Error('not found')), + getCircuitZkey: vi.fn().mockRejectedValue(new Error('not found')), + }; + await expect( + generateProof(CircuitType.Disclosure, VALID_INPUTS, { provider: badProvider }) + ).rejects.toBeInstanceOf(CircuitNotFoundError); + }); + + it('throws InvalidInputsError for null input value', async () => { + await expect( + generateProof(CircuitType.Disclosure, { commitment: null as any }, { provider }) + ).rejects.toBeInstanceOf(InvalidInputsError); + }); + + it('throws ProofGenerationError when snarkjs fullProve throws', async () => { + const snarkjs = await import('snarkjs'); + vi.mocked(snarkjs.groth16.fullProve).mockRejectedValueOnce(new Error('proving failed')); + await expect( + generateProof(CircuitType.Disclosure, VALID_INPUTS, { provider }) + ).rejects.toBeInstanceOf(ProofGenerationError); + }); +}); + +// ─── arkworks backend ───────────────────────────────────────────────────────── + +describe('generateProof — arkworks backend', () => { + let provider: ArtifactProvider; + + beforeEach(() => { + vi.clearAllMocks(); + provider = makeArkworksProvider(); + }); + + it('returns ProofResult with proof and publicSignals', async () => { + const result = await generateProof(CircuitType.Disclosure, VALID_INPUTS, { + provider, + backend: 'arkworks', + }); + expect(result.proof).toMatch(/^0x[0-9a-f]+$/i); + expect(result.publicSignals).toHaveLength(4); + expect(result.circuitType).toBe(CircuitType.Disclosure); + }); + + it('uses snarkjs wtns.calculate (not fullProve) for witness', async () => { + const snarkjs = await import('snarkjs'); + await generateProof(CircuitType.Disclosure, VALID_INPUTS, { provider, backend: 'arkworks' }); + expect(snarkjs.wtns.calculate).toHaveBeenCalledTimes(1); + expect(snarkjs.groth16.fullProve).not.toHaveBeenCalled(); + }); + + it('fetches WASM and .ark proving key from provider', async () => { + await generateProof(CircuitType.Disclosure, VALID_INPUTS, { provider, backend: 'arkworks' }); + expect(provider.getCircuitWasm).toHaveBeenCalledWith(CircuitType.Disclosure); + expect(provider.getCircuitProvingKey).toHaveBeenCalledWith(CircuitType.Disclosure); + expect(provider.getCircuitZkey).not.toHaveBeenCalled(); + }); + + it('passes witness decimal JSON and .ark bytes to WASM', async () => { + const wasm = await import('@orbinum/groth16-proofs'); + await generateProof(CircuitType.Disclosure, VALID_INPUTS, { provider, backend: 'arkworks' }); + expect(wasm.generate_proof_from_decimal_wasm).toHaveBeenCalledTimes(1); + const [numSigs, witnessJson, pkBytes] = ( + wasm.generate_proof_from_decimal_wasm as ReturnType + ).mock.calls[0]; + expect(numSigs).toBe(4); + const parsed = JSON.parse(witnessJson); + expect(Array.isArray(parsed)).toBe(true); + expect(parsed[0]).toBe('1'); + expect(pkBytes).toBe(FAKE_ARK); + }); + + it('throws CircuitNotFoundError when provider rejects on proving key fetch', async () => { + const badProvider: ArtifactProvider = { + getCircuitWasm: vi.fn().mockResolvedValue(FAKE_WASM), + getCircuitZkey: vi.fn().mockResolvedValue(FAKE_ZKEY), + getCircuitProvingKey: vi.fn().mockRejectedValue(new Error('ark not found')), + }; + await expect( + generateProof(CircuitType.Disclosure, VALID_INPUTS, { + provider: badProvider, + backend: 'arkworks', + }) + ).rejects.toBeInstanceOf(CircuitNotFoundError); + }); + + it('throws CircuitNotFoundError when provider has no getCircuitProvingKey', async () => { + const noArkProvider: ArtifactProvider = { + getCircuitWasm: vi.fn().mockResolvedValue(FAKE_WASM), + getCircuitZkey: vi.fn().mockResolvedValue(FAKE_ZKEY), + }; + await expect( + generateProof(CircuitType.Disclosure, VALID_INPUTS, { + provider: noArkProvider, + backend: 'arkworks', + }) + ).rejects.toBeInstanceOf(CircuitNotFoundError); + }); + + it('throws ProofGenerationError when WASM proof generation throws', async () => { + const wasm = await import('@orbinum/groth16-proofs'); + vi.mocked(wasm.generate_proof_from_decimal_wasm).mockImplementationOnce(() => { + throw new Error('bad proving key'); + }); + await expect( + generateProof(CircuitType.Disclosure, VALID_INPUTS, { provider, backend: 'arkworks' }) + ).rejects.toBeInstanceOf(ProofGenerationError); + }); + + it('throws InvalidInputsError for null input value', async () => { + await expect( + generateProof( + CircuitType.Disclosure, + { commitment: null as any }, + { + provider, + backend: 'arkworks', + } + ) + ).rejects.toBeInstanceOf(InvalidInputsError); + }); +}); diff --git a/tests/generate/provider.test.ts b/tests/generate/provider.test.ts new file mode 100644 index 0000000..22329ac --- /dev/null +++ b/tests/generate/provider.test.ts @@ -0,0 +1,46 @@ +/** + * Tests: generate/provider.ts — resolveProvider() + * + * Verifies that the correct default provider is auto-selected based on + * the environment, and that explicit overrides are passed through as-is. + */ + +import { describe, it, expect, vi, afterEach } from 'vitest'; +import { resolveProvider } from '../../src/generate/provider'; +import { NodeArtifactProvider } from '../../src/providers/node'; +import { WebArtifactProvider } from '../../src/providers/web'; +import type { ArtifactProvider } from '../../src/providers/interface'; + +afterEach(() => { + vi.unstubAllGlobals(); +}); + +describe('resolveProvider', () => { + it('returns the override provider unchanged when provided', () => { + const custom: ArtifactProvider = { + getCircuitWasm: vi.fn(), + getCircuitZkey: vi.fn(), + }; + expect(resolveProvider(custom)).toBe(custom); + }); + + it('returns NodeArtifactProvider when window and self are undefined (Node.js)', () => { + vi.stubGlobal('window', undefined); + vi.stubGlobal('self', undefined); + const provider = resolveProvider(); + expect(provider).toBeInstanceOf(NodeArtifactProvider); + }); + + it('returns WebArtifactProvider when window is defined (browser)', () => { + vi.stubGlobal('window', {}); + const provider = resolveProvider(); + expect(provider).toBeInstanceOf(WebArtifactProvider); + }); + + it('returns WebArtifactProvider when self is defined (web worker)', () => { + vi.stubGlobal('window', undefined); + vi.stubGlobal('self', {}); + const provider = resolveProvider(); + expect(provider).toBeInstanceOf(WebArtifactProvider); + }); +}); diff --git a/tests/integration/disclosure.test.ts b/tests/integration/disclosure.test.ts deleted file mode 100644 index ad765b2..0000000 --- a/tests/integration/disclosure.test.ts +++ /dev/null @@ -1,131 +0,0 @@ -/** - * Integration Test: Disclosure Circuit - * - * Tests the complete proof generation flow for selective disclosure: - * - Commitment verification - * - Selective information reveal - * - Owner identity masking - * - Verification key hashing - * - Zero-knowledge proof generation - * - * This is an integration test that validates the selective disclosure protocol - * allowing users to prove ownership without revealing all note details. - */ - -// @ts-ignore - circomlibjs doesn't have types -import { buildPoseidon } from 'circomlibjs'; -import { generateProof, CircuitType } from '../../src'; - -describe('Integration: Disclosure Proof Generation', () => { - let poseidon: any; - - beforeAll(async () => { - // Initialize Poseidon - poseidon = await buildPoseidon(); - }); - - it('should generate a valid disclosure proof', async () => { - const F = poseidon.F; - - // Create note - const noteValue = BigInt('100000000000000000000'); - const assetId = BigInt(0); - const ownerPubkey = BigInt('0x' + '2'.repeat(64)); - const blinding = BigInt('0x' + '9'.repeat(64)); - - // Compute commitment = Poseidon(value, asset_id, owner_pubkey, blinding) - const commitment = poseidon([noteValue, assetId, ownerPubkey, blinding]); - const commitmentBigInt = F.toObject(commitment); - - // Compute revealed_owner_hash = Poseidon(owner_pubkey) for this test - const revealedOwnerHash = poseidon([ownerPubkey]); - const revealedOwnerHashBigInt = F.toObject(revealedOwnerHash); - - // Prepare inputs (matching disclosure.circom) - const inputs = { - // Public inputs - commitment: commitmentBigInt.toString(), - revealed_value: '0', // 0 = oculto - revealed_asset_id: '0', // 0 = oculto - revealed_owner_hash: revealedOwnerHashBigInt.toString(), // Revelado - // Private inputs - value: noteValue.toString(), - asset_id: assetId.toString(), - owner_pubkey: ownerPubkey.toString(), - blinding: blinding.toString(), - // Disclosure masks - disclose_value: '0', // 0 = no revelar - disclose_asset_id: '0', // 0 = no revelar - disclose_owner: '1', // 1 = revelar - }; - - // Generate proof - try { - const result = await generateProof(CircuitType.Disclosure, inputs); - - // Assertions - Basic structure - expect(result).toBeDefined(); - expect(result.proof).toMatch(/^0x[0-9a-f]+$/); - expect(result.publicSignals).toHaveLength(4); - expect(result.circuitType).toBe(CircuitType.Disclosure); - - // Verify proof size (128 bytes = 256 hex chars + 0x prefix) - const proofBytes = Buffer.from(result.proof.slice(2), 'hex'); - expect(proofBytes.length).toBe(128); - - // Verify public signals format - all should be hex strings - result.publicSignals.forEach((signal, idx) => { - expect(signal).toMatch(/^0x[0-9a-f]+$/); - // Each signal should be 32 bytes (64 hex chars + 0x) - expect(signal.length).toBe(66); // 0x + 64 hex chars - }); - - // Verify public signals match inputs - // Order: commitment, revealed_value, revealed_asset_id, revealed_owner_hash - expect(result.publicSignals[0]).toBeDefined(); // commitment - expect(result.publicSignals[1]).toBeDefined(); // revealed_value (0) - expect(result.publicSignals[2]).toBeDefined(); // revealed_asset_id (0) - expect(result.publicSignals[3]).toBeDefined(); // revealed_owner_hash - } catch (error: any) { - // Skip test if WASM fails to load (can happen in certain test environments) - if (error.message?.includes('WASM') || error.message?.includes('export')) { - return; // Silently skip test - } - // If artifacts are not available, skip - if (error.message.includes('Circuit not found') || error.message.includes('ENOENT')) { - console.warn('⚠️ Skipping: Circuit artifacts not available'); - return; - } - throw error; - } - }, 30000); // 30 second timeout - - it('should fail with invalid inputs', async () => { - await expect( - generateProof(CircuitType.Disclosure, { - commitment: 'invalid', - }) - ).rejects.toThrow(); - }); - - it('should fail with missing required fields', async () => { - await expect( - generateProof(CircuitType.Disclosure, { - commitment: '123', - // Missing other required fields - }) - ).rejects.toThrow(); - }); - - it('should fail with null/undefined inputs', async () => { - await expect( - // @ts-ignore - Testing invalid input - generateProof(CircuitType.Disclosure, null) - ).rejects.toThrow(); - - await expect( - // @ts-ignore - Testing invalid input - generateProof(CircuitType.Disclosure, undefined) - ).rejects.toThrow(); - }); -}); diff --git a/tests/integration/transfer.test.ts b/tests/integration/transfer.test.ts deleted file mode 100644 index c703c7e..0000000 --- a/tests/integration/transfer.test.ts +++ /dev/null @@ -1,257 +0,0 @@ -/** - * Integration Test: Transfer Circuit - * - * Tests the complete proof generation flow for private Transfer circuit: - * - EdDSA signature generation (BabyJub curve) - * - Multiple input notes (2 inputs → 2 outputs) - * - Merkle proof verification - * - Nullifier computation - * - Balance conservation check - * - Witness calculation and proof generation - * - * This is an integration test that validates the full private transfer flow - * including cryptographic signatures and zero-knowledge proof generation. - */ - -// @ts-ignore - circomlibjs doesn't have types -import { buildPoseidon, buildEddsa, buildBabyjub } from 'circomlibjs'; -import { generateProof, CircuitType } from '../../src'; - -describe('Integration: Transfer Proof Generation', () => { - let poseidon: any; - let eddsa: any; - let babyJub: any; - - beforeAll(async () => { - // Initialize crypto primitives - poseidon = await buildPoseidon(); - eddsa = await buildEddsa(); - babyJub = await buildBabyjub(); - }); - - it('should generate a valid transfer proof', async () => { - const F = poseidon.F; - - // Generate EdDSA keypairs for input note owners - const prvKey1 = Buffer.from( - '0001020304050607080900010203040506070809000102030405060708090001', - 'hex' - ); - const prvKey2 = Buffer.from( - '0102030405060708090001020304050607080900010203040506070809000102', - 'hex' - ); - - const pubKey1 = eddsa.prv2pub(prvKey1); - const pubKey2 = eddsa.prv2pub(prvKey2); - - // Extract Ax (x-coordinate) as owner_pubkey - const ownerPubkey1 = F.toObject(pubKey1[0]); - const ownerPubkey2 = F.toObject(pubKey2[0]); - - // Create two input notes - const inputValue1 = BigInt('100000000000000000000'); - const inputValue2 = BigInt('50000000000000000000'); - const assetId = BigInt(0); - const blinding1 = BigInt('0x' + '9'.repeat(64)); - const blinding2 = BigInt('0x' + '8'.repeat(64)); - const spendingKey1 = BigInt('0x' + '4'.repeat(64)); - const spendingKey2 = BigInt('0x' + '5'.repeat(64)); - - // Compute input commitments - const commitment1 = poseidon([inputValue1, assetId, ownerPubkey1, blinding1]); - const commitment1BigInt = F.toObject(commitment1); - - const commitment2 = poseidon([inputValue2, assetId, ownerPubkey2, blinding2]); - const commitment2BigInt = F.toObject(commitment2); - - // Sign commitments with EdDSA (to prove ownership) - // Note: signPoseidon expects BabyJub field elements - const F_babyJub = babyJub.F; - const signature1 = eddsa.signPoseidon(prvKey1, F_babyJub.e(commitment1BigInt)); - const signature2 = eddsa.signPoseidon(prvKey2, F_babyJub.e(commitment2BigInt)); - - // Compute nullifiers - const nullifier1 = poseidon([commitment1BigInt, spendingKey1]); - const nullifier1BigInt = F.toObject(nullifier1); - - const nullifier2 = poseidon([commitment2BigInt, spendingKey2]); - const nullifier2BigInt = F.toObject(nullifier2); - - // Build Merkle tree with BOTH commitments - // Tree structure (2 leaves at depth 0): - // root - // / \ - // h01 h23 - // / \ / \ - // c1 c2 0 0 - - // Level 0: Hash the two commitments - const level0_01 = F.toObject(poseidon([commitment1BigInt, commitment2BigInt])); - const level0_23 = F.toObject(poseidon([BigInt(0), BigInt(0)])); - - // Level 1: Hash pairs from level 0 - let merkleRoot = F.toObject(poseidon([level0_01, level0_23])); - - // Continue hashing up to depth 20 - for (let i = 2; i < 20; i++) { - merkleRoot = F.toObject(poseidon([merkleRoot, BigInt(0)])); - } - - // Build merkle path for commitment1 (at index 0) - const pathElements1 = []; - const pathIndices1 = []; - - pathElements1.push(commitment2BigInt.toString()); // Sibling at level 0 - pathIndices1.push(0); // We're on the left - - pathElements1.push(level0_23.toString()); // Sibling at level 1 - pathIndices1.push(0); // We're on the left - - // Rest of the path is zeros - for (let i = 2; i < 20; i++) { - pathElements1.push('0'); - pathIndices1.push(0); - } - - // Build merkle path for commitment2 (at index 1) - const pathElements2 = []; - const pathIndices2 = []; - - pathElements2.push(commitment1BigInt.toString()); // Sibling at level 0 - pathIndices2.push(1); // We're on the right - - pathElements2.push(level0_23.toString()); // Sibling at level 1 - pathIndices2.push(0); // We're on the left - - // Rest of the path is zeros - for (let i = 2; i < 20; i++) { - pathElements2.push('0'); - pathIndices2.push(0); - } - - // Create two output notes - const outputValue1 = BigInt('80000000000000000000'); - const outputValue2 = BigInt('70000000000000000000'); - const outputOwner1 = BigInt('0x' + '6'.repeat(64)); - const outputOwner2 = BigInt('0x' + '7'.repeat(64)); - const outputBlinding1 = BigInt('0x' + 'a'.repeat(64)); - const outputBlinding2 = BigInt('0x' + 'b'.repeat(64)); - - // Compute output commitments - const outputCommitment1 = poseidon([outputValue1, assetId, outputOwner1, outputBlinding1]); - const outputCommitment1BigInt = F.toObject(outputCommitment1); - - const outputCommitment2 = poseidon([outputValue2, assetId, outputOwner2, outputBlinding2]); - const outputCommitment2BigInt = F.toObject(outputCommitment2); - - // Prepare inputs (following circuit signal names exactly) - const inputs = { - // Public inputs - merkle_root: merkleRoot.toString(), - nullifiers: [nullifier1BigInt.toString(), nullifier2BigInt.toString()], - commitments: [outputCommitment1BigInt.toString(), outputCommitment2BigInt.toString()], - - // Private inputs - Input notes - input_values: [inputValue1.toString(), inputValue2.toString()], - input_asset_ids: [assetId.toString(), assetId.toString()], - input_blindings: [blinding1.toString(), blinding2.toString()], - spending_keys: [spendingKey1.toString(), spendingKey2.toString()], - - // EdDSA public keys (Ax, Ay) - input_owner_Ax: [F.toObject(pubKey1[0]).toString(), F.toObject(pubKey2[0]).toString()], - input_owner_Ay: [F.toObject(pubKey1[1]).toString(), F.toObject(pubKey2[1]).toString()], - - // EdDSA signatures (R8x, R8y, S) - input_sig_R8x: [ - F.toObject(signature1.R8[0]).toString(), - F.toObject(signature2.R8[0]).toString(), - ], - input_sig_R8y: [ - F.toObject(signature1.R8[1]).toString(), - F.toObject(signature2.R8[1]).toString(), - ], - input_sig_S: [signature1.S.toString(), signature2.S.toString()], - - // Merkle proofs (2D arrays) - input_path_elements: [pathElements1, pathElements2], - input_path_indices: [pathIndices1, pathIndices2], - - // Output notes - output_values: [outputValue1.toString(), outputValue2.toString()], - output_asset_ids: [assetId.toString(), assetId.toString()], - output_owner_pubkeys: [outputOwner1.toString(), outputOwner2.toString()], - output_blindings: [outputBlinding1.toString(), outputBlinding2.toString()], - }; - - // Generate proof - try { - const result = await generateProof(CircuitType.Transfer, inputs); - - // Assertions - Basic structure - expect(result).toBeDefined(); - expect(result.proof).toMatch(/^0x[0-9a-f]+$/); - expect(result.publicSignals).toHaveLength(5); - expect(result.circuitType).toBe(CircuitType.Transfer); - - // Verify proof size (128 bytes = 256 hex chars + 0x prefix) - const proofBytes = Buffer.from(result.proof.slice(2), 'hex'); - expect(proofBytes.length).toBe(128); - - // Verify public signals format - all should be hex strings - result.publicSignals.forEach((signal, idx) => { - expect(signal).toMatch(/^0x[0-9a-f]+$/); - // Each signal should be 32 bytes (64 hex chars + 0x) - expect(signal.length).toBe(66); // 0x + 64 hex chars - }); - - // Verify public signals match inputs - // Order: merkle_root, nullifiers[2], commitments[2] - expect(result.publicSignals[0]).toBeDefined(); // merkle_root - expect(result.publicSignals[1]).toBeDefined(); // nullifiers[0] - expect(result.publicSignals[2]).toBeDefined(); // nullifiers[1] - expect(result.publicSignals[3]).toBeDefined(); // commitments[0] - expect(result.publicSignals[4]).toBeDefined(); // commitments[1] - } catch (error: any) { - // Skip test if WASM fails to load (can happen in certain test environments) - if (error.message?.includes('WASM') || error.message?.includes('export')) { - return; // Silently skip test - } - // If artifacts are not available, skip - if (error.message.includes('Circuit not found') || error.message.includes('ENOENT')) { - console.warn('⚠️ Skipping: Circuit artifacts not available'); - return; - } - throw error; - } - }, 30000); // 30 second timeout - - it('should fail with invalid inputs', async () => { - await expect( - generateProof(CircuitType.Transfer, { - merkle_root: 'invalid', - }) - ).rejects.toThrow(); - }); - - it('should fail with missing required fields', async () => { - await expect( - generateProof(CircuitType.Transfer, { - merkle_root: '123', - // Missing other required fields - }) - ).rejects.toThrow(); - }); - - it('should fail with null/undefined inputs', async () => { - await expect( - // @ts-ignore - Testing invalid input - generateProof(CircuitType.Transfer, null) - ).rejects.toThrow(); - - await expect( - // @ts-ignore - Testing invalid input - generateProof(CircuitType.Transfer, undefined) - ).rejects.toThrow(); - }); -}); diff --git a/tests/integration/unshield.test.ts b/tests/integration/unshield.test.ts deleted file mode 100644 index bc4e12b..0000000 --- a/tests/integration/unshield.test.ts +++ /dev/null @@ -1,146 +0,0 @@ -/** - * Integration Test: Unshield Circuit - * - * Tests the complete proof generation flow for Unshield circuit: - * - Circuit artifact loading - * - Poseidon hash computation - * - Merkle tree construction - * - Witness calculation (snarkjs) - * - Proof generation (arkworks) - * - Proof compression (128 bytes) - * - * This is an integration test that uses real circuit artifacts and cryptography. - */ - -// @ts-ignore - circomlibjs doesn't have types -import { buildPoseidon } from 'circomlibjs'; -import { generateProof, CircuitType } from '../../src'; - -describe('Integration: Unshield Proof Generation', () => { - let poseidon: any; - - beforeAll(async () => { - // Initialize Poseidon - poseidon = await buildPoseidon(); - }); - - it('should generate a valid unshield proof', async () => { - const F = poseidon.F; - - // Create note - const noteValue = BigInt('100000000000000000000'); - const assetId = BigInt(0); - const ownerPubkey = BigInt('0x' + '2'.repeat(64)); - const blinding = BigInt('0x' + '9'.repeat(64)); - const spendingKey = BigInt('0x' + '4'.repeat(64)); - - // Compute commitment - const commitment = poseidon([noteValue, assetId, ownerPubkey, blinding]); - const commitmentBigInt = F.toObject(commitment); - - // Compute nullifier - const nullifier = poseidon([commitmentBigInt, spendingKey]); - const nullifierBigInt = F.toObject(nullifier); - - // Build Merkle tree - let currentHash = commitmentBigInt; - const pathElements = []; - const pathIndices = []; - - for (let i = 0; i < 20; i++) { - pathIndices.push(0); - pathElements.push('0'); - const parent = poseidon([currentHash, 0]); - currentHash = F.toObject(parent); - } - - const merkleRoot = currentHash; - const recipient = BigInt('0x' + '5'.repeat(40)); - - // Prepare inputs - const inputs = { - merkle_root: merkleRoot.toString(), - nullifier: nullifierBigInt.toString(), - amount: noteValue.toString(), - recipient: recipient.toString(), - asset_id: assetId.toString(), - note_value: noteValue.toString(), - note_asset_id: assetId.toString(), - note_owner: ownerPubkey.toString(), - note_blinding: blinding.toString(), - spending_key: spendingKey.toString(), - path_elements: pathElements, - path_indices: pathIndices, - }; - - // Generate proof - try { - const result = await generateProof(CircuitType.Unshield, inputs); - - // Assertions - Basic structure - expect(result).toBeDefined(); - expect(result.proof).toMatch(/^0x[0-9a-f]+$/); - expect(result.publicSignals).toHaveLength(5); - expect(result.circuitType).toBe(CircuitType.Unshield); - - // Verify proof size (128 bytes = 256 hex chars + 0x prefix) - const proofBytes = Buffer.from(result.proof.slice(2), 'hex'); - expect(proofBytes.length).toBe(128); - - // Verify public signals format - all should be hex strings - result.publicSignals.forEach((signal, idx) => { - expect(signal).toMatch(/^0x[0-9a-f]+$/); - // Each signal should be 32 bytes (64 hex chars + 0x) - expect(signal.length).toBe(66); // 0x + 64 hex chars - }); - - // Verify public signals match inputs (order: merkle_root, nullifier, amount, recipient, asset_id) - // Note: Signals are in little-endian format from the circuit - expect(result.publicSignals[0]).toBeDefined(); // merkle_root - expect(result.publicSignals[1]).toBeDefined(); // nullifier - expect(result.publicSignals[2]).toBeDefined(); // amount - expect(result.publicSignals[3]).toBeDefined(); // recipient - expect(result.publicSignals[4]).toBeDefined(); // asset_id - } catch (error: any) { - // Skip test if WASM fails to load (can happen in certain test environments) - if (error.message?.includes('WASM') || error.message?.includes('export')) { - return; // Silently skip test - } - throw error; - } - - // Logs comentados - descomentar para debugging - // console.log('✅ Proof generated successfully'); - // console.log(' Proof size:', proofBytes.length, 'bytes'); - // console.log(' Public signals:', result.publicSignals.length); - // console.log(' Public signals format validated: ✓'); - }, 30000); // 30 second timeout - - it('should fail with invalid inputs', async () => { - const invalidInputs = { - merkle_root: 'invalid', - // missing other required fields - }; - - await expect(generateProof(CircuitType.Unshield, invalidInputs)).rejects.toThrow(); - }); - - it('should fail with missing required fields', async () => { - const incompleteInputs = { - merkle_root: '123', - nullifier: '456', - // missing amount, recipient, asset_id, etc. - }; - - await expect(generateProof(CircuitType.Unshield, incompleteInputs)).rejects.toThrow(); - }); - - it('should fail with null/undefined inputs', async () => { - const nullInputs = { - merkle_root: null, - nullifier: undefined, - }; - - await expect(generateProof(CircuitType.Unshield, nullInputs as any)).rejects.toThrow(); - }); -}); diff --git a/tests/providers/node.test.ts b/tests/providers/node.test.ts new file mode 100644 index 0000000..a0a7a71 --- /dev/null +++ b/tests/providers/node.test.ts @@ -0,0 +1,157 @@ +/** + * Tests: NodeArtifactProvider + * + * Tests use a temporary directory with fake artifact files to avoid + * dependence on the actual @orbinum/circuits package being installed. + */ + +import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import * as fs from 'fs'; +import * as os from 'os'; +import * as path from 'path'; +import { NodeArtifactProvider } from '../../src/providers'; +import { CircuitType } from '../../src/circuits/types'; + +// ─── Temporary artifact directory ──────────────────────────────────────────── + +let tmpDir: string; + +beforeAll(() => { + tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'orbinum-test-')); + + // Create fake artifact files the provider will look for + const artifacts = [ + 'unshield.wasm', + 'unshield_pk.zkey', + 'unshield_pk.ark', + 'transfer.wasm', + 'transfer_pk.zkey', + 'transfer_pk.ark', + 'disclosure.wasm', + 'disclosure_pk.zkey', + 'disclosure_pk.ark', + 'private_link.wasm', + 'private_link_pk.zkey', + 'private_link_pk.ark', + ]; + for (const file of artifacts) { + fs.writeFileSync(path.join(tmpDir, file), Buffer.from(`fake-${file}`)); + } +}); + +afterAll(() => { + fs.rmSync(tmpDir, { recursive: true, force: true }); +}); + +// ─── Tests ──────────────────────────────────────────────────────────────────── + +describe('NodeArtifactProvider', () => { + it('constructs successfully with an explicit packageRoot', () => { + expect(() => new NodeArtifactProvider(tmpDir)).not.toThrow(); + }); + + it('reads WASM file for Unshield circuit', async () => { + const provider = new NodeArtifactProvider(tmpDir); + const result = await provider.getCircuitWasm(CircuitType.Unshield); + expect(result).toBeInstanceOf(Uint8Array); + expect(result.length).toBeGreaterThan(0); + }); + + it('reads zkey file for Unshield circuit', async () => { + const provider = new NodeArtifactProvider(tmpDir); + const result = await provider.getCircuitZkey(CircuitType.Unshield); + expect(result).toBeInstanceOf(Uint8Array); + expect(result.length).toBeGreaterThan(0); + }); + + it('reads WASM file for Transfer circuit', async () => { + const provider = new NodeArtifactProvider(tmpDir); + const result = await provider.getCircuitWasm(CircuitType.Transfer); + expect(result).toBeInstanceOf(Uint8Array); + }); + + it('reads WASM file for Disclosure circuit', async () => { + const provider = new NodeArtifactProvider(tmpDir); + const result = await provider.getCircuitWasm(CircuitType.Disclosure); + expect(result).toBeInstanceOf(Uint8Array); + }); + + it('reads WASM file for PrivateLink circuit', async () => { + const provider = new NodeArtifactProvider(tmpDir); + const result = await provider.getCircuitWasm(CircuitType.PrivateLink); + expect(result).toBeInstanceOf(Uint8Array); + }); + + it('returns content matching the fake file', async () => { + const provider = new NodeArtifactProvider(tmpDir); + const result = await provider.getCircuitWasm(CircuitType.Unshield); + const text = Buffer.from(result as Uint8Array).toString('utf8'); + expect(text).toBe('fake-unshield.wasm'); + }); + + it('throws when artifact file does not exist', async () => { + const emptyDir = fs.mkdtempSync(path.join(os.tmpdir(), 'orbinum-empty-')); + try { + const provider = new NodeArtifactProvider(emptyDir); + await expect(provider.getCircuitWasm(CircuitType.Unshield)).rejects.toThrow( + 'Artifact unshield.wasm not found' + ); + } finally { + fs.rmSync(emptyDir, { recursive: true, force: true }); + } + }); + + it('reads .ark proving key for Unshield circuit', async () => { + const provider = new NodeArtifactProvider(tmpDir); + const result = await provider.getCircuitProvingKey!(CircuitType.Unshield); + expect(result).toBeInstanceOf(Uint8Array); + expect(result.length).toBeGreaterThan(0); + }); + + it('.ark content matches fake file', async () => { + const provider = new NodeArtifactProvider(tmpDir); + const result = await provider.getCircuitProvingKey!(CircuitType.Unshield); + expect(Buffer.from(result).toString('utf8')).toBe('fake-unshield_pk.ark'); + }); + + it('reads .ark proving key for all circuit types', async () => { + const provider = new NodeArtifactProvider(tmpDir); + const types = [ + CircuitType.Unshield, + CircuitType.Transfer, + CircuitType.Disclosure, + CircuitType.PrivateLink, + ]; + for (const type of types) { + const result = await provider.getCircuitProvingKey!(type); + expect(result).toBeInstanceOf(Uint8Array); + } + }); + + it('throws when .ark file does not exist', async () => { + // directory has no .ark files + const noArkDir = fs.mkdtempSync(path.join(os.tmpdir(), 'orbinum-noark-')); + fs.writeFileSync(path.join(noArkDir, 'unshield.wasm'), 'fake'); + fs.writeFileSync(path.join(noArkDir, 'unshield_pk.zkey'), 'fake'); + try { + const provider = new NodeArtifactProvider(noArkDir); + await expect(provider.getCircuitProvingKey!(CircuitType.Unshield)).rejects.toThrow( + 'Artifact unshield_pk.ark not found' + ); + } finally { + fs.rmSync(noArkDir, { recursive: true, force: true }); + } + }); + + it('throws when packageRoot cannot be resolved and no arg given', () => { + // If @orbinum/circuits is not installed, construction should throw. + // If it IS installed (CI), this test is skipped gracefully. + try { + const provider = new NodeArtifactProvider(); + // If we get here the package is installed — just verify it constructed + expect(provider).toBeDefined(); + } catch (err: any) { + expect(err.message).toMatch(/Cannot resolve @orbinum\/circuits/); + } + }); +}); diff --git a/tests/providers/web.test.ts b/tests/providers/web.test.ts new file mode 100644 index 0000000..775dd4c --- /dev/null +++ b/tests/providers/web.test.ts @@ -0,0 +1,351 @@ +/** + * Tests: WebArtifactProvider + * + * Two modes: + * - Legacy (string arg): direct URL construction, no manifest fetch. + * - Manifest (no arg / options object): fetches manifest.json from npm CDN, + * resolves versioned artifact URLs from it. + */ + +import { describe, it, expect, beforeEach, vi } from 'vitest'; +import { WebArtifactProvider } from '../../src/providers'; +import { CircuitType } from '../../src/circuits/types'; + +// ─── Shared mock manifest ───────────────────────────────────────────────────── + +const MOCK_PKG_VERSION = '0.4.4'; + +function buildMockManifest(overrides?: { + unshieldActiveVersion?: number; + supportedVersions?: number[]; +}) { + return { + schema_version: '1.0.0', + package_name: 'orbinum-circuits', + package_version: MOCK_PKG_VERSION, + generated_at: '2026-03-19T14:10:04.861Z', + circuits: { + unshield: { + active_version: overrides?.unshieldActiveVersion ?? 1, + supported_versions: overrides?.supportedVersions ?? [1], + versions: { + '1': { + version: 1, + vk_hash: '0x73401aa0', + artifacts: { + wasm: { file: 'unshield.wasm', bytes: 2396830, sha256: 'aaa' }, + zkey: { file: 'unshield_pk.zkey', bytes: 5326768, sha256: 'bbb' }, + vk_json: { file: 'verification_key_unshield.json', bytes: 3657, sha256: 'ccc' }, + r1cs: { file: 'unshield.r1cs', bytes: 1584412, sha256: 'ddd' }, + ark: { file: 'unshield_pk.ark', bytes: 192, sha256: 'eee' }, + }, + }, + '2': { + version: 2, + vk_hash: '0xdeadbeef', + artifacts: { + wasm: { file: 'unshield_v2.wasm', bytes: 2500000, sha256: 'eee' }, + zkey: { file: 'unshield_v2_pk.zkey', bytes: 6000000, sha256: 'fff' }, + vk_json: { file: 'verification_key_unshield_v2.json', bytes: 3700, sha256: 'ggg' }, + r1cs: { file: 'unshield_v2.r1cs', bytes: 1700000, sha256: 'hhh' }, + ark: { file: 'unshield_v2_pk.ark', bytes: 192, sha256: 'iii' }, + }, + }, + }, + }, + transfer: { + active_version: 1, + supported_versions: [1], + versions: { + '1': { + version: 1, + vk_hash: '0x2ab60d15', + artifacts: { + wasm: { file: 'transfer.wasm', bytes: 3359868, sha256: 'iii' }, + zkey: { file: 'transfer_pk.zkey', bytes: 20484784, sha256: 'jjj' }, + vk_json: { file: 'verification_key_transfer.json', bytes: 3658, sha256: 'kkk' }, + r1cs: { file: 'transfer.r1cs', bytes: 6629624, sha256: 'lll' }, + }, + }, + }, + }, + }, + }; +} + +function mockManifestThenArtifact() { + vi.stubGlobal( + 'fetch', + vi + .fn() + .mockResolvedValueOnce({ ok: true, json: async () => buildMockManifest() }) + .mockResolvedValueOnce({ ok: true, arrayBuffer: async () => new ArrayBuffer(8) }) + ); +} + +// ─── Legacy mode ───────────────────────────────────────────────────────────── + +describe('WebArtifactProvider — legacy mode (string URL)', () => { + const baseUrl = 'https://test.orbinum.com/circuits'; + + beforeEach(() => { + vi.unstubAllGlobals(); + vi.stubGlobal( + 'fetch', + vi.fn().mockResolvedValue({ ok: true, arrayBuffer: async () => new ArrayBuffer(8) }) + ); + }); + + it('constructs correct WASM URL', async () => { + const provider = new WebArtifactProvider(baseUrl); + await provider.getCircuitWasm(CircuitType.Unshield); + + expect(global.fetch).toHaveBeenCalledTimes(1); + expect((global.fetch as ReturnType).mock.calls[0][0]).toBe( + 'https://test.orbinum.com/circuits/unshield.wasm' + ); + }); + + it('constructs correct zkey URL', async () => { + const provider = new WebArtifactProvider(baseUrl); + await provider.getCircuitZkey(CircuitType.Transfer); + + expect((global.fetch as ReturnType).mock.calls[0][0]).toBe( + 'https://test.orbinum.com/circuits/transfer_pk.zkey' + ); + }); + + it('constructs correct .ark URL', async () => { + const provider = new WebArtifactProvider(baseUrl); + await provider.getCircuitProvingKey!(CircuitType.Unshield); + + expect((global.fetch as ReturnType).mock.calls[0][0]).toBe( + 'https://test.orbinum.com/circuits/unshield_pk.ark' + ); + }); + + it('throws on failed fetch', async () => { + vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ ok: false, status: 404 })); + const provider = new WebArtifactProvider(baseUrl); + + await expect(provider.getCircuitWasm(CircuitType.Unshield)).rejects.toThrow( + 'Failed to fetch circuit artifact' + ); + }); + + it('strips trailing slash from base URL', async () => { + const provider = new WebArtifactProvider('https://slash.com/'); + await provider.getCircuitWasm(CircuitType.Unshield); + + const url = (global.fetch as ReturnType).mock.calls[0][0]; + expect(url).toBe('https://slash.com/unshield.wasm'); + }); + + it('returns Uint8Array from ArrayBuffer', async () => { + const provider = new WebArtifactProvider(baseUrl); + const result = await provider.getCircuitWasm(CircuitType.Unshield); + expect(result).toBeInstanceOf(Uint8Array); + }); +}); + +// ─── Manifest mode ──────────────────────────────────────────────────────────── + +describe('WebArtifactProvider — manifest mode (npm CDN)', () => { + beforeEach(() => { + vi.unstubAllGlobals(); + }); + + it('fetches manifest then pins WASM URL to package_version', async () => { + mockManifestThenArtifact(); + + const provider = new WebArtifactProvider(); + await provider.getCircuitWasm(CircuitType.Unshield); + + expect(global.fetch).toHaveBeenCalledTimes(2); + expect((global.fetch as ReturnType).mock.calls[0][0]).toBe( + 'https://unpkg.com/@orbinum/circuits/manifest.json' + ); + expect((global.fetch as ReturnType).mock.calls[1][0]).toBe( + `https://unpkg.com/@orbinum/circuits@${MOCK_PKG_VERSION}/unshield.wasm` + ); + }); + + it('pins zkey URL to package_version', async () => { + mockManifestThenArtifact(); + + const provider = new WebArtifactProvider(); + await provider.getCircuitZkey(CircuitType.Transfer); + + expect((global.fetch as ReturnType).mock.calls[1][0]).toBe( + `https://unpkg.com/@orbinum/circuits@${MOCK_PKG_VERSION}/transfer_pk.zkey` + ); + }); + + it('caches manifest — two artifact fetches = 3 total fetch calls', async () => { + vi.stubGlobal( + 'fetch', + vi + .fn() + .mockResolvedValueOnce({ ok: true, json: async () => buildMockManifest() }) + .mockResolvedValue({ ok: true, arrayBuffer: async () => new ArrayBuffer(8) }) + ); + + const provider = new WebArtifactProvider(); + await provider.getCircuitWasm(CircuitType.Unshield); + await provider.getCircuitZkey(CircuitType.Unshield); + + expect(global.fetch).toHaveBeenCalledTimes(3); + }); + + it('manifest is fetched only once across concurrent requests', async () => { + vi.stubGlobal( + 'fetch', + vi + .fn() + .mockResolvedValueOnce({ ok: true, json: async () => buildMockManifest() }) + .mockResolvedValue({ ok: true, arrayBuffer: async () => new ArrayBuffer(8) }) + ); + + const provider = new WebArtifactProvider(); + await Promise.all([ + provider.getCircuitWasm(CircuitType.Unshield), + provider.getCircuitZkey(CircuitType.Unshield), + ]); + + const manifestCalls = (global.fetch as ReturnType).mock.calls.filter(args => + (args[0] as string).includes('manifest.json') + ); + expect(manifestCalls).toHaveLength(1); + }); + + it('circuitVersions override uses the specified version filename', async () => { + vi.stubGlobal( + 'fetch', + vi + .fn() + .mockResolvedValueOnce({ + ok: true, + json: async () => + buildMockManifest({ unshieldActiveVersion: 2, supportedVersions: [1, 2] }), + }) + .mockResolvedValueOnce({ ok: true, arrayBuffer: async () => new ArrayBuffer(8) }) + ); + + const provider = new WebArtifactProvider({ circuitVersions: { unshield: 1 } }); + await provider.getCircuitWasm(CircuitType.Unshield); + + const artifactUrl = (global.fetch as ReturnType).mock.calls[1][0]; + // v1 filename is 'unshield.wasm' + expect(artifactUrl).toBe( + `https://unpkg.com/@orbinum/circuits@${MOCK_PKG_VERSION}/unshield.wasm` + ); + }); + + it('throws when requested circuit version is not in supported_versions', async () => { + vi.stubGlobal( + 'fetch', + vi.fn().mockResolvedValueOnce({ + ok: true, + json: async () => buildMockManifest({ unshieldActiveVersion: 2, supportedVersions: [2] }), + }) + ); + + const provider = new WebArtifactProvider({ circuitVersions: { unshield: 1 } }); + await expect(provider.getCircuitWasm(CircuitType.Unshield)).rejects.toThrow( + 'no longer supported' + ); + }); + + it('throws when manifest fetch fails', async () => { + vi.stubGlobal('fetch', vi.fn().mockResolvedValueOnce({ ok: false, status: 503 })); + + const provider = new WebArtifactProvider(); + await expect(provider.getCircuitWasm(CircuitType.Unshield)).rejects.toThrow( + 'Failed to fetch circuits manifest' + ); + }); + + it('uses custom baseUrl for manifest and artifacts', async () => { + const mirror = 'https://my-mirror.io/circuits'; + vi.stubGlobal( + 'fetch', + vi + .fn() + .mockResolvedValueOnce({ ok: true, json: async () => buildMockManifest() }) + .mockResolvedValueOnce({ ok: true, arrayBuffer: async () => new ArrayBuffer(8) }) + ); + + const provider = new WebArtifactProvider({ baseUrl: mirror }); + await provider.getCircuitWasm(CircuitType.Unshield); + + expect((global.fetch as ReturnType).mock.calls[0][0]).toBe( + `${mirror}/manifest.json` + ); + expect((global.fetch as ReturnType).mock.calls[1][0]).toBe( + `${mirror}/unshield.wasm` + ); + }); + + it('throws when artifact fetch fails', async () => { + vi.stubGlobal( + 'fetch', + vi + .fn() + .mockResolvedValueOnce({ ok: true, json: async () => buildMockManifest() }) + .mockResolvedValueOnce({ ok: false, status: 404 }) + ); + + const provider = new WebArtifactProvider(); + await expect(provider.getCircuitWasm(CircuitType.Unshield)).rejects.toThrow( + 'Failed to fetch circuit artifact' + ); + }); + + it('fetches .ark URL from manifest ark entry', async () => { + vi.stubGlobal( + 'fetch', + vi + .fn() + .mockResolvedValueOnce({ ok: true, json: async () => buildMockManifest() }) + .mockResolvedValueOnce({ ok: true, arrayBuffer: async () => new ArrayBuffer(8) }) + ); + + const provider = new WebArtifactProvider(); + await provider.getCircuitProvingKey!(CircuitType.Unshield); + + expect((global.fetch as ReturnType).mock.calls[1][0]).toBe( + `https://unpkg.com/@orbinum/circuits@${MOCK_PKG_VERSION}/unshield_pk.ark` + ); + }); + + it('derives .ark filename by convention when manifest has no ark entry', async () => { + // transfer circuit in the mock manifest has no ark entry + vi.stubGlobal( + 'fetch', + vi + .fn() + .mockResolvedValueOnce({ ok: true, json: async () => buildMockManifest() }) + .mockResolvedValueOnce({ ok: true, arrayBuffer: async () => new ArrayBuffer(8) }) + ); + + const provider = new WebArtifactProvider(); + await provider.getCircuitProvingKey!(CircuitType.Transfer); + + const url = (global.fetch as ReturnType).mock.calls[1][0]; + expect(url).toBe(`https://unpkg.com/@orbinum/circuits@${MOCK_PKG_VERSION}/transfer_pk.ark`); + }); + + it('getCircuitProvingKey returns Uint8Array', async () => { + vi.stubGlobal( + 'fetch', + vi + .fn() + .mockResolvedValueOnce({ ok: true, json: async () => buildMockManifest() }) + .mockResolvedValueOnce({ ok: true, arrayBuffer: async () => new ArrayBuffer(8) }) + ); + + const provider = new WebArtifactProvider(); + const result = await provider.getCircuitProvingKey!(CircuitType.Unshield); + expect(result).toBeInstanceOf(Uint8Array); + }); +}); diff --git a/tests/unit/circuits.test.ts b/tests/unit/circuits.test.ts deleted file mode 100644 index d8bf43d..0000000 --- a/tests/unit/circuits.test.ts +++ /dev/null @@ -1,83 +0,0 @@ -/** - * Unit Tests: circuits.ts - * - * Tests circuit configuration resolution and validation - */ - -import { getCircuitConfig, NodeArtifactProvider } from '../../src/circuits'; -import { CircuitType } from '../../src/types'; -import * as fs from 'fs'; - -describe('circuits.ts - Unit Tests', () => { - describe('getCircuitConfig', () => { - it('should return config for Unshield circuit', () => { - const config = getCircuitConfig(CircuitType.Unshield); - - expect(config).toBeDefined(); - expect(config.name).toBe('unshield'); - expect(config.wasmPath).toBe('unshield.wasm'); - expect(config.zkeyPath).toBe('unshield_pk.zkey'); - expect(config.provingKeyPath).toBe('unshield_pk.ark'); - expect(config.expectedPublicSignals).toBe(5); - }); - - it('should return config for Transfer circuit', () => { - const config = getCircuitConfig(CircuitType.Transfer); - - expect(config).toBeDefined(); - expect(config.name).toBe('transfer'); - expect(config.wasmPath).toBe('transfer.wasm'); - expect(config.zkeyPath).toBe('transfer_pk.zkey'); - expect(config.provingKeyPath).toBe('transfer_pk.ark'); - expect(config.expectedPublicSignals).toBe(5); - }); - - it('should return config for Disclosure circuit', () => { - const config = getCircuitConfig(CircuitType.Disclosure); - - expect(config).toBeDefined(); - expect(config.name).toBe('disclosure'); - expect(config.wasmPath).toBe('disclosure.wasm'); - expect(config.zkeyPath).toBe('disclosure_pk.zkey'); - expect(config.provingKeyPath).toBe('disclosure_pk.ark'); - expect(config.expectedPublicSignals).toBe(4); - }); - - it('should return config for PrivateLink circuit', () => { - const config = getCircuitConfig(CircuitType.PrivateLink); - - expect(config).toBeDefined(); - expect(config.name).toBe('private_link'); - expect(config.wasmPath).toBe('private_link.wasm'); - expect(config.zkeyPath).toBe('private_link_pk.zkey'); - expect(config.provingKeyPath).toBe('private_link_pk.ark'); - expect(config.expectedPublicSignals).toBe(2); - }); - }); - - describe('NodeArtifactProvider', () => { - it('should resolve artifacts via fs', async () => { - const provider = new NodeArtifactProvider(); - - const wasm = await provider.getCircuitWasm(CircuitType.Unshield); - const zkey = await provider.getCircuitZkey(CircuitType.Unshield); - - expect(wasm).toBeDefined(); - expect(zkey).toBeDefined(); - expect(wasm.length).toBeGreaterThan(0); - expect(zkey.length).toBeGreaterThan(0); - }); - - it('should fail if artifacts are missing', async () => { - // We expect it to succeed if env is correct, - // but let's test that it throws with invalid package root if forced - try { - const provider = new NodeArtifactProvider('/invalid/path'); - await provider.getCircuitWasm(CircuitType.Unshield); - fail('Should have thrown'); - } catch (e) { - expect((e as Error).message).toContain('not found'); - } - }); - }); -}); diff --git a/tests/unit/disclosure.test.ts b/tests/unit/disclosure.test.ts deleted file mode 100644 index e6be472..0000000 --- a/tests/unit/disclosure.test.ts +++ /dev/null @@ -1,571 +0,0 @@ -/** - * Unit Tests: disclosure.ts - * - * Tests the high-level `generateDisclosureProof` API and its helpers. - * - * Strategy: - * - Mock `circomlibjs` to avoid running real Poseidon (no circuit artifacts needed). - * - Mock `../../src/index` (generateProof) to return crafted public signals. - * - Test everything the disclosure orchestrator does: - * 1. Mask validation (all-false must throw) - * 2. Circuit inputs built with correct values - * 3. `revealedData` decoded correctly from public signals for all mask combos - * 4. Proof / publicSignals forwarded as-is - * 5. Helper round-trips: bigIntToBytes32 ↔ bytes32ToBigInt - */ - -import { generateDisclosureProof } from '../../src/disclosure'; -import { DisclosureMask, CircuitType } from '../../src/types'; -import { bigIntToBytes32, bytes32ToBigInt } from '../../src/utils'; - -// ============================================================================ -// Mocks -// ============================================================================ - -// Fixed mock viewing key returned by the mocked Poseidon hasher. -// Using 999n so it's easy to recognise in assertions. -const MOCK_VIEWING_KEY = 999n; - -// Little-endian hex encoding of MOCK_VIEWING_KEY (32 bytes): -// 999 = 0x3E7 → byte[0]=0xE7, byte[1]=0x03, rest 0 -const MOCK_VIEWING_KEY_LE_HEX = - '0xe703000000000000000000000000000000000000000000000000000000000000'; - -// Little-endian hex for 0n (all zeros, same byte order either way) -const ZERO_LE_HEX = '0x0000000000000000000000000000000000000000000000000000000000000000'; - -// Little-endian hex for value=100n (0x64 → byte[0]=0x64, rest 0) -const VALUE_100_LE_HEX = '0x6400000000000000000000000000000000000000000000000000000000000000'; - -// Little-endian hex for assetId=7n (0x07 → byte[0]=0x07, rest 0) -const ASSET_7_LE_HEX = '0x0700000000000000000000000000000000000000000000000000000000000000'; - -// Commitment: just use a fixed LE hex (any non-zero value) -const COMMITMENT_HEX = '0x0102030400000000000000000000000000000000000000000000000000000000'; - -// Mock circomlibjs: buildPoseidon returns a minimal Poseidon stand-in. -jest.mock('circomlibjs', () => ({ - buildPoseidon: jest.fn().mockResolvedValue( - Object.assign((_inputs: any[]) => ({ _isMockFieldElement: true }), { - F: { - // toObject always returns the mock viewing key — enough to exercise the flow. - toObject: (_: any) => BigInt(999), - }, - }) - ), -})); - -// generateProof is mocked at the module level so that no artifacts are needed. -// Tests can override the resolved value for individual scenarios. -const mockGenerateProof = jest.fn(); - -jest.mock('../../src/index', () => { - const original = jest.requireActual('../../src/index'); - return { - ...original, - generateProof: (...args: any[]) => mockGenerateProof(...args), - }; -}); - -// ============================================================================ -// Test data -// ============================================================================ - -const NOTE_VALUE = 100n; -const OWNER_PUBKEY = BigInt('0x' + '2'.repeat(64)); -const BLINDING = BigInt('0x' + '9'.repeat(64)); -const ASSET_ID = 7n; -const COMMITMENT = BigInt('0x0102030400000000000000000000000000000000000000000000000000000000'); - -/** Build a mock ProofResult whose public signals reflect the given mask. */ -function buildMockResult(mask: DisclosureMask) { - return { - proof: '0x' + 'ab'.repeat(128), - publicSignals: [ - COMMITMENT_HEX, - mask.discloseValue ? VALUE_100_LE_HEX : ZERO_LE_HEX, - mask.discloseAssetId ? ASSET_7_LE_HEX : ZERO_LE_HEX, - mask.discloseOwner ? MOCK_VIEWING_KEY_LE_HEX : ZERO_LE_HEX, - ], - circuitType: CircuitType.Disclosure, - }; -} - -// ============================================================================ -// Helper tests (pure functions — no mocks needed) -// ============================================================================ - -describe('disclosure.ts helpers - bigIntToBytes32 / bytes32ToBigInt', () => { - it('should round-trip zero', () => { - const bytes = bigIntToBytes32(0n); - expect(bytes).toHaveLength(32); - expect(bytes.every(b => b === 0)).toBe(true); - expect(bytes32ToBigInt(bytes)).toBe(0n); - }); - - it('should round-trip small values', () => { - for (const n of [1n, 100n, 255n, 256n, 65535n]) { - expect(bytes32ToBigInt(bigIntToBytes32(n))).toBe(n); - } - }); - - it('should round-trip large BN254 field element', () => { - // BN254 prime - 1 - const big = 21888242871839275222246405745257275088548364400416034343698204186575808495616n; - expect(bytes32ToBigInt(bigIntToBytes32(big))).toBe(big); - }); - - it('should encode in big-endian (MSB at index 0)', () => { - const bytes = bigIntToBytes32(256n); // 0x0100 - expect(bytes[30]).toBe(1); - expect(bytes[31]).toBe(0); - }); -}); - -// ============================================================================ -// Mask validation -// ============================================================================ - -describe('generateDisclosureProof - mask validation', () => { - beforeEach(() => { - mockGenerateProof.mockResolvedValue( - buildMockResult({ discloseValue: true, discloseAssetId: false, discloseOwner: false }) - ); - }); - - it('should throw when all mask flags are false', async () => { - const mask: DisclosureMask = { - discloseValue: false, - discloseAssetId: false, - discloseOwner: false, - }; - - await expect( - generateDisclosureProof(NOTE_VALUE, OWNER_PUBKEY, BLINDING, ASSET_ID, COMMITMENT, mask) - ).rejects.toThrow(/DisclosureMask/); - }); - - it('should NOT throw when at least one flag is true (discloseValue)', async () => { - const mask: DisclosureMask = { - discloseValue: true, - discloseAssetId: false, - discloseOwner: false, - }; - - await expect( - generateDisclosureProof(NOTE_VALUE, OWNER_PUBKEY, BLINDING, ASSET_ID, COMMITMENT, mask) - ).resolves.toBeDefined(); - }); - - it('should NOT throw when at least one flag is true (discloseOwner)', async () => { - mockGenerateProof.mockResolvedValue( - buildMockResult({ discloseValue: false, discloseAssetId: false, discloseOwner: true }) - ); - const mask: DisclosureMask = { - discloseValue: false, - discloseAssetId: false, - discloseOwner: true, - }; - - await expect( - generateDisclosureProof(NOTE_VALUE, OWNER_PUBKEY, BLINDING, ASSET_ID, COMMITMENT, mask) - ).resolves.toBeDefined(); - }); -}); - -// ============================================================================ -// Circuit inputs built correctly -// ============================================================================ - -describe('generateDisclosureProof - circuit inputs', () => { - beforeEach(() => { - mockGenerateProof.mockResolvedValue( - buildMockResult({ discloseValue: true, discloseAssetId: true, discloseOwner: true }) - ); - }); - - it('should call generateProof with CircuitType.Disclosure', async () => { - const mask: DisclosureMask = { - discloseValue: true, - discloseAssetId: true, - discloseOwner: true, - }; - - await generateDisclosureProof(NOTE_VALUE, OWNER_PUBKEY, BLINDING, ASSET_ID, COMMITMENT, mask); - - expect(mockGenerateProof).toHaveBeenCalledWith( - CircuitType.Disclosure, - expect.any(Object), - expect.any(Object) - ); - }); - - it('should include commitment in circuit inputs', async () => { - const mask: DisclosureMask = { - discloseValue: true, - discloseAssetId: false, - discloseOwner: false, - }; - mockGenerateProof.mockResolvedValue(buildMockResult(mask)); - - await generateDisclosureProof(NOTE_VALUE, OWNER_PUBKEY, BLINDING, ASSET_ID, COMMITMENT, mask); - - const [, inputs] = mockGenerateProof.mock.calls.at(-1)!; - expect(inputs.commitment).toBe(COMMITMENT.toString()); - }); - - it('should set disclose_value=1 when mask.discloseValue is true', async () => { - const mask: DisclosureMask = { - discloseValue: true, - discloseAssetId: false, - discloseOwner: false, - }; - - await generateDisclosureProof(NOTE_VALUE, OWNER_PUBKEY, BLINDING, ASSET_ID, COMMITMENT, mask); - - const [, inputs] = mockGenerateProof.mock.calls.at(-1)!; - expect(inputs.disclose_value).toBe('1'); - expect(inputs.disclose_asset_id).toBe('0'); - expect(inputs.disclose_owner).toBe('0'); - }); - - it('should set all disclose flags correctly for all-reveal mask', async () => { - const mask: DisclosureMask = { - discloseValue: true, - discloseAssetId: true, - discloseOwner: true, - }; - - await generateDisclosureProof(NOTE_VALUE, OWNER_PUBKEY, BLINDING, ASSET_ID, COMMITMENT, mask); - - const [, inputs] = mockGenerateProof.mock.calls.at(-1)!; - expect(inputs.disclose_value).toBe('1'); - expect(inputs.disclose_asset_id).toBe('1'); - expect(inputs.disclose_owner).toBe('1'); - }); - - it('should set revealed_value=0 in public inputs when discloseValue is false', async () => { - const mask: DisclosureMask = { - discloseValue: false, - discloseAssetId: true, - discloseOwner: false, - }; - mockGenerateProof.mockResolvedValue(buildMockResult(mask)); - - await generateDisclosureProof(NOTE_VALUE, OWNER_PUBKEY, BLINDING, ASSET_ID, COMMITMENT, mask); - - const [, inputs] = mockGenerateProof.mock.calls.at(-1)!; - expect(inputs.revealed_value).toBe('0'); - }); - - it('should set revealed_value=value in public inputs when discloseValue is true', async () => { - const mask: DisclosureMask = { - discloseValue: true, - discloseAssetId: false, - discloseOwner: false, - }; - - await generateDisclosureProof(NOTE_VALUE, OWNER_PUBKEY, BLINDING, ASSET_ID, COMMITMENT, mask); - - const [, inputs] = mockGenerateProof.mock.calls.at(-1)!; - expect(inputs.revealed_value).toBe(NOTE_VALUE.toString()); - }); - - it('should set revealed_asset_id=asset_id when discloseAssetId is true', async () => { - const mask: DisclosureMask = { - discloseValue: false, - discloseAssetId: true, - discloseOwner: false, - }; - mockGenerateProof.mockResolvedValue(buildMockResult(mask)); - - await generateDisclosureProof(NOTE_VALUE, OWNER_PUBKEY, BLINDING, ASSET_ID, COMMITMENT, mask); - - const [, inputs] = mockGenerateProof.mock.calls.at(-1)!; - expect(inputs.revealed_asset_id).toBe(ASSET_ID.toString()); - }); - - it('should set revealed_owner_hash=viewingKey when discloseOwner is true', async () => { - const mask: DisclosureMask = { - discloseValue: false, - discloseAssetId: false, - discloseOwner: true, - }; - mockGenerateProof.mockResolvedValue(buildMockResult(mask)); - - await generateDisclosureProof(NOTE_VALUE, OWNER_PUBKEY, BLINDING, ASSET_ID, COMMITMENT, mask); - - const [, inputs] = mockGenerateProof.mock.calls.at(-1)!; - expect(inputs.revealed_owner_hash).toBe(MOCK_VIEWING_KEY.toString()); - }); - - it('should set revealed_asset_id=0 when discloseAssetId is false', async () => { - const mask: DisclosureMask = { - discloseValue: true, - discloseAssetId: false, - discloseOwner: false, - }; - - await generateDisclosureProof(NOTE_VALUE, OWNER_PUBKEY, BLINDING, ASSET_ID, COMMITMENT, mask); - - const [, inputs] = mockGenerateProof.mock.calls.at(-1)!; - expect(inputs.revealed_asset_id).toBe('0'); - }); - - it('should set revealed_owner_hash=0 when discloseOwner is false', async () => { - const mask: DisclosureMask = { - discloseValue: true, - discloseAssetId: false, - discloseOwner: false, - }; - - await generateDisclosureProof(NOTE_VALUE, OWNER_PUBKEY, BLINDING, ASSET_ID, COMMITMENT, mask); - - const [, inputs] = mockGenerateProof.mock.calls.at(-1)!; - expect(inputs.revealed_owner_hash).toBe('0'); - }); - - it('should include all private inputs (value, asset_id, owner_pubkey, blinding)', async () => { - const mask: DisclosureMask = { - discloseValue: true, - discloseAssetId: true, - discloseOwner: true, - }; - - await generateDisclosureProof(NOTE_VALUE, OWNER_PUBKEY, BLINDING, ASSET_ID, COMMITMENT, mask); - - const [, inputs] = mockGenerateProof.mock.calls.at(-1)!; - expect(inputs.value).toBeDefined(); - expect(inputs.asset_id).toBeDefined(); - expect(inputs.owner_pubkey).toBe(OWNER_PUBKEY.toString()); - expect(inputs.blinding).toBe(BLINDING.toString()); - }); - - it('should forward options.provider to generateProof as 3rd argument', async () => { - const mask: DisclosureMask = { - discloseValue: true, - discloseAssetId: false, - discloseOwner: false, - }; - const fakeProvider = { getCircuitWasm: jest.fn(), getCircuitZkey: jest.fn() } as any; - - await generateDisclosureProof(NOTE_VALUE, OWNER_PUBKEY, BLINDING, ASSET_ID, COMMITMENT, mask, { - provider: fakeProvider, - }); - - const [, , opts] = mockGenerateProof.mock.calls.at(-1)!; - expect(opts.provider).toBe(fakeProvider); - }); -}); - -// ============================================================================ -// revealedData decoding -// ============================================================================ - -describe('generateDisclosureProof - revealedData decoding', () => { - it('should include commitment in revealedData regardless of mask', async () => { - const mask: DisclosureMask = { - discloseValue: true, - discloseAssetId: false, - discloseOwner: false, - }; - mockGenerateProof.mockResolvedValue(buildMockResult(mask)); - - const result = await generateDisclosureProof( - NOTE_VALUE, - OWNER_PUBKEY, - BLINDING, - ASSET_ID, - COMMITMENT, - mask - ); - - expect(result.revealedData.commitment).toBe(COMMITMENT_HEX); - }); - - it('should decode value when discloseValue=true', async () => { - const mask: DisclosureMask = { - discloseValue: true, - discloseAssetId: false, - discloseOwner: false, - }; - mockGenerateProof.mockResolvedValue(buildMockResult(mask)); - - const result = await generateDisclosureProof( - NOTE_VALUE, - OWNER_PUBKEY, - BLINDING, - ASSET_ID, - COMMITMENT, - mask - ); - - // value=100n → LE hex → decoded back to '100' - expect(result.revealedData.value).toBe('100'); - expect(result.revealedData.assetId).toBeUndefined(); - expect(result.revealedData.ownerHash).toBeUndefined(); - }); - - it('should decode assetId when discloseAssetId=true', async () => { - const mask: DisclosureMask = { - discloseValue: false, - discloseAssetId: true, - discloseOwner: false, - }; - mockGenerateProof.mockResolvedValue(buildMockResult(mask)); - - const result = await generateDisclosureProof( - NOTE_VALUE, - OWNER_PUBKEY, - BLINDING, - ASSET_ID, - COMMITMENT, - mask - ); - - // assetId=7n → LE hex → decoded back to 7 - expect(result.revealedData.assetId).toBe(7); - expect(result.revealedData.value).toBeUndefined(); - expect(result.revealedData.ownerHash).toBeUndefined(); - }); - - it('should decode ownerHash when discloseOwner=true', async () => { - const mask: DisclosureMask = { - discloseValue: false, - discloseAssetId: false, - discloseOwner: true, - }; - mockGenerateProof.mockResolvedValue(buildMockResult(mask)); - - const result = await generateDisclosureProof( - NOTE_VALUE, - OWNER_PUBKEY, - BLINDING, - ASSET_ID, - COMMITMENT, - mask - ); - - // ownerHash → decoded from LE hex of MOCK_VIEWING_KEY = 999n - expect(result.revealedData.ownerHash).toBe( - '0x' + MOCK_VIEWING_KEY.toString(16).padStart(64, '0') - ); - expect(result.revealedData.value).toBeUndefined(); - expect(result.revealedData.assetId).toBeUndefined(); - }); - - it('should decode all 3 fields when mask is all-true', async () => { - const mask: DisclosureMask = { - discloseValue: true, - discloseAssetId: true, - discloseOwner: true, - }; - mockGenerateProof.mockResolvedValue(buildMockResult(mask)); - - const result = await generateDisclosureProof( - NOTE_VALUE, - OWNER_PUBKEY, - BLINDING, - ASSET_ID, - COMMITMENT, - mask - ); - - expect(result.revealedData.value).toBe('100'); - expect(result.revealedData.assetId).toBe(7); - expect(result.revealedData.ownerHash).toBeDefined(); - expect(result.revealedData.commitment).toBe(COMMITMENT_HEX); - }); - - it('should forward proof and publicSignals as-is from generateProof', async () => { - const mask: DisclosureMask = { - discloseValue: true, - discloseAssetId: false, - discloseOwner: false, - }; - const mockResult = buildMockResult(mask); - mockGenerateProof.mockResolvedValue(mockResult); - - const result = await generateDisclosureProof( - NOTE_VALUE, - OWNER_PUBKEY, - BLINDING, - ASSET_ID, - COMMITMENT, - mask - ); - - expect(result.proof).toBe(mockResult.proof); - expect(result.publicSignals).toEqual(mockResult.publicSignals); - }); -}); - -// ============================================================================ -// All 7 valid mask combinations (2^3 - 1) -// ============================================================================ - -describe('generateDisclosureProof - all 7 valid mask combinations', () => { - const VALID_MASKS: DisclosureMask[] = [ - { discloseValue: true, discloseAssetId: false, discloseOwner: false }, - { discloseValue: false, discloseAssetId: true, discloseOwner: false }, - { discloseValue: false, discloseAssetId: false, discloseOwner: true }, - { discloseValue: true, discloseAssetId: true, discloseOwner: false }, - { discloseValue: true, discloseAssetId: false, discloseOwner: true }, - { discloseValue: false, discloseAssetId: true, discloseOwner: true }, - { discloseValue: true, discloseAssetId: true, discloseOwner: true }, - ]; - - test.each(VALID_MASKS)('mask V=%s A=%s O=%s should resolve without error', async mask => { - mockGenerateProof.mockResolvedValue(buildMockResult(mask)); - - const result = await generateDisclosureProof( - NOTE_VALUE, - OWNER_PUBKEY, - BLINDING, - ASSET_ID, - COMMITMENT, - mask - ); - - expect(result).toBeDefined(); - expect(result.proof).toBeDefined(); - expect(result.publicSignals).toHaveLength(4); - expect(result.revealedData.commitment).toBeDefined(); - - // Fields present iff their mask flag is true - if (mask.discloseValue) { - expect(result.revealedData.value).toBeDefined(); - } else { - expect(result.revealedData.value).toBeUndefined(); - } - if (mask.discloseAssetId) { - expect(result.revealedData.assetId).toBeDefined(); - } else { - expect(result.revealedData.assetId).toBeUndefined(); - } - if (mask.discloseOwner) { - expect(result.revealedData.ownerHash).toBeDefined(); - } else { - expect(result.revealedData.ownerHash).toBeUndefined(); - } - }); -}); - -// ============================================================================ -// Error propagation from generateProof -// ============================================================================ - -describe('generateDisclosureProof - error propagation', () => { - it('should propagate errors from generateProof', async () => { - const mask: DisclosureMask = { - discloseValue: true, - discloseAssetId: false, - discloseOwner: false, - }; - mockGenerateProof.mockRejectedValue(new Error('Circuit not found')); - - await expect( - generateDisclosureProof(NOTE_VALUE, OWNER_PUBKEY, BLINDING, ASSET_ID, COMMITMENT, mask) - ).rejects.toThrow('Circuit not found'); - }); -}); diff --git a/tests/unit/index.test.ts b/tests/unit/index.test.ts deleted file mode 100644 index 2b4b6a8..0000000 --- a/tests/unit/index.test.ts +++ /dev/null @@ -1,119 +0,0 @@ -/** - * Unit Tests: index.ts - * - * Tests main API functions with isolated unit testing approach - */ - -import { CircuitType } from '../../src'; - -describe('index.ts - Unit Tests', () => { - // Tests for isReady were removed as the function was deprecated - - describe('CircuitType enum', () => { - it('should define all circuit types', () => { - expect(CircuitType.Unshield).toBeDefined(); - expect(CircuitType.Transfer).toBeDefined(); - expect(CircuitType.Disclosure).toBeDefined(); - expect(CircuitType.PrivateLink).toBeDefined(); - }); - - it('should have string values', () => { - expect(typeof CircuitType.Unshield).toBe('string'); - expect(typeof CircuitType.Transfer).toBe('string'); - expect(typeof CircuitType.Disclosure).toBe('string'); - expect(typeof CircuitType.PrivateLink).toBe('string'); - }); - - it('should have lowercase circuit names', () => { - expect(CircuitType.Unshield).toBe('unshield'); - expect(CircuitType.Transfer).toBe('transfer'); - expect(CircuitType.Disclosure).toBe('disclosure'); - expect(CircuitType.PrivateLink).toBe('private_link'); - }); - }); - - describe('Error types', () => { - it('should export custom error types', () => { - const { - CircuitNotFoundError, - ProofGenerationError, - InvalidInputsError, - } = require('../../src/types'); - - expect(CircuitNotFoundError).toBeDefined(); - expect(ProofGenerationError).toBeDefined(); - expect(InvalidInputsError).toBeDefined(); - }); - - it('should create CircuitNotFoundError instances', () => { - const { CircuitNotFoundError, CircuitType } = require('../../src/types'); - const error = new CircuitNotFoundError(CircuitType.Unshield); - - expect(error).toBeInstanceOf(Error); - // expect(error.name).toBe('ProofGeneratorError'); // Base class name might vary - expect(error.message).toContain('unshield'); - expect(error.message).toContain('Circuit not found'); - }); - - it('should create ProofGenerationError instances', () => { - const { ProofGenerationError } = require('../../src/types'); - const error = new ProofGenerationError('test message'); - - expect(error).toBeInstanceOf(Error); - // expect(error.name).toBe('ProofGeneratorError'); - expect(error.message).toBe('test message'); - }); - - it('should create InvalidInputsError instances', () => { - const { InvalidInputsError } = require('../../src/types'); - const error = new InvalidInputsError('invalid input'); - - expect(error).toBeInstanceOf(Error); - // expect(error.name).toBe('ProofGeneratorError'); // Base class name - expect(error.message).toBe('invalid input'); - }); - }); - - describe('Module exports', () => { - it('should export generateProof function', () => { - const { generateProof } = require('../../src'); - expect(typeof generateProof).toBe('function'); - }); - - // isReady removed - - // calculateWitness removed - - it('should export all utility functions', () => { - const { - validateInputs, - validatePublicSignals, - validateProofSize, - normalizeProofHex, - } = require('../../src'); - - expect(typeof validateInputs).toBe('function'); - expect(typeof validatePublicSignals).toBe('function'); - expect(typeof validateProofSize).toBe('function'); - expect(typeof normalizeProofHex).toBe('function'); - }); - - it('should export CircuitType enum', () => { - const { CircuitType } = require('../../src'); - expect(CircuitType).toBeDefined(); - expect(CircuitType.Unshield).toBeDefined(); - }); - - it('should export error classes', () => { - const { - CircuitNotFoundError, - ProofGenerationError, - InvalidInputsError, - } = require('../../src'); - - expect(CircuitNotFoundError).toBeDefined(); - expect(ProofGenerationError).toBeDefined(); - expect(InvalidInputsError).toBeDefined(); - }); - }); -}); diff --git a/tests/unit/provider.test.ts b/tests/unit/provider.test.ts deleted file mode 100644 index be07ac5..0000000 --- a/tests/unit/provider.test.ts +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Unit Tests: provider.ts - * - * Tests the WebArtifactProvider implementation using mocked fetch. - */ - -import { WebArtifactProvider, getCircuitConfig } from '../../src/circuits'; -import { CircuitType } from '../../src/types'; - -// Mock global fetch -global.fetch = jest.fn(); - -describe('WebArtifactProvider', () => { - let provider: WebArtifactProvider; - const baseUrl = 'https://test.orbinum.com/circuits'; - - beforeEach(() => { - jest.resetAllMocks(); - provider = new WebArtifactProvider(baseUrl); - }); - - it('should construct correct URLs for WASM', async () => { - (global.fetch as jest.Mock).mockResolvedValue({ - ok: true, - arrayBuffer: async () => new ArrayBuffer(8), - }); - - await provider.getCircuitWasm(CircuitType.Unshield); - - expect(global.fetch).toHaveBeenCalledTimes(1); - const url = (global.fetch as jest.Mock).mock.calls[0][0]; - expect(url).toBe('https://test.orbinum.com/circuits/unshield.wasm'); - }); - - it('should construct correct URLs for zkey', async () => { - (global.fetch as jest.Mock).mockResolvedValue({ - ok: true, - arrayBuffer: async () => new ArrayBuffer(8), - }); - - await provider.getCircuitZkey(CircuitType.Transfer); - - expect(global.fetch).toHaveBeenCalledTimes(1); - const url = (global.fetch as jest.Mock).mock.calls[0][0]; - expect(url).toBe('https://test.orbinum.com/circuits/transfer_pk.zkey'); - }); - - it('should throw error on failed fetch', async () => { - (global.fetch as jest.Mock).mockResolvedValue({ - ok: false, - status: 404, - }); - - await expect(provider.getCircuitWasm(CircuitType.Unshield)).rejects.toThrow( - 'Failed to fetch circuit artifact' - ); - }); - - it('should handle trailing slash in base URL', async () => { - const providerWithSlash = new WebArtifactProvider('https://slash.com/'); - - (global.fetch as jest.Mock).mockResolvedValue({ - ok: true, - arrayBuffer: async () => new ArrayBuffer(8), - }); - - await providerWithSlash.getCircuitWasm(CircuitType.Unshield); - - const url = (global.fetch as jest.Mock).mock.calls[0][0]; - expect(url).toBe('https://slash.com/unshield.wasm'); - }); -}); diff --git a/tests/unit/utils.test.ts b/tests/unit/utils.test.ts deleted file mode 100644 index d7baf69..0000000 --- a/tests/unit/utils.test.ts +++ /dev/null @@ -1,143 +0,0 @@ -/** - * Unit Tests: utils.ts - * - * Tests for validation and formatting utilities - */ - -import { - validateInputs, - validateProofSize, - validatePublicSignals, - normalizeProofHex, - formatProofHexForDisplay, -} from '../../src/utils'; - -describe('Utils', () => { - describe('normalizeProofHex', () => { - it('should add 0x prefix', () => { - const hex = 'ABCD' + '00'.repeat(126); - const normalized = normalizeProofHex(hex); - - expect(normalized).toMatch(/^0x[0-9a-f]{256}$/); - expect(normalized.substring(0, 6)).toBe('0xabcd'); - }); - - it('should lowercase hex', () => { - const hex = '0xABCD' + '00'.repeat(126); - const normalized = normalizeProofHex(hex); - - expect(normalized.substring(0, 6)).toBe('0xabcd'); - }); - }); - - describe('formatProofHexForDisplay', () => { - it('should truncate long hex', () => { - const hex = '0x' + 'ab'.repeat(128); - const display = formatProofHexForDisplay(hex, 20); - - expect(display.length).toBeLessThan(hex.length); - expect(display).toContain('...'); - }); - - it('should not truncate short hex', () => { - const hex = '0xabcd'; - const display = formatProofHexForDisplay(hex, 20); - - expect(display).toBe(hex); - }); - }); - - describe('validateInputs', () => { - it('should accept valid inputs', () => { - const inputs = { a: '1', b: '2', c: ['3', '4'] }; - expect(() => validateInputs(inputs)).not.toThrow(); - }); - - it('should accept nested objects', () => { - const inputs = { a: '1', b: { nested: '2' }, c: ['3', '4'] }; - expect(() => validateInputs(inputs)).not.toThrow(); - }); - - it('should reject null inputs', () => { - expect(() => validateInputs(null as any)).toThrow('Inputs must be an object'); - }); - - it('should reject undefined inputs', () => { - expect(() => validateInputs(undefined as any)).toThrow('Inputs must be an object'); - }); - - it('should reject undefined values', () => { - const inputs = { a: '1', b: undefined }; - expect(() => validateInputs(inputs)).toThrow(/is undefined or null/); - }); - - it('should reject null values', () => { - const inputs = { a: '1', b: null }; - expect(() => validateInputs(inputs)).toThrow(/is undefined or null/); - }); - }); - - describe('validateProofSize', () => { - it('should accept 128-byte proof', () => { - const proof = '0x' + '00'.repeat(128); - expect(() => validateProofSize(proof)).not.toThrow(); - }); - - it('should accept proof without 0x prefix', () => { - const proof = '00'.repeat(128); - expect(() => validateProofSize(proof)).not.toThrow(); - }); - - it('should reject 64-byte proof', () => { - const proof = '0x' + '00'.repeat(64); - expect(() => validateProofSize(proof)).toThrow( - /Invalid proof size.*expected 256 hex chars.*got 128 chars/ - ); - }); - - it('should reject 256-byte proof (uncompressed)', () => { - const proof = '0x' + '00'.repeat(256); - expect(() => validateProofSize(proof)).toThrow( - /Invalid proof size.*expected 256 hex chars.*got 512 chars/ - ); - }); - - it('should reject empty proof', () => { - const proof = '0x'; - expect(() => validateProofSize(proof)).toThrow( - /Invalid proof size.*expected 256 hex chars.*got 0 chars/ - ); - }); - }); - - describe('validatePublicSignals', () => { - it('should accept correct count', () => { - const signals = ['1', '2', '3', '4', '5']; - expect(() => validatePublicSignals(signals, 5)).not.toThrow(); - }); - - it('should reject wrong count (too few)', () => { - const signals = ['1', '2', '3']; - expect(() => validatePublicSignals(signals, 5)).toThrow( - /Invalid public signals count.*expected 5.*got 3/ - ); - }); - - it('should reject wrong count (too many)', () => { - const signals = ['1', '2', '3', '4', '5', '6', '7']; - expect(() => validatePublicSignals(signals, 5)).toThrow( - /Invalid public signals count.*expected 5.*got 7/ - ); - }); - - it('should accept empty signals when expected is 0', () => { - const signals: string[] = []; - expect(() => validatePublicSignals(signals, 0)).not.toThrow(); - }); - - it('should handle disclosure circuit (4 signals)', () => { - const signals = ['1', '2', '3', '4']; - expect(() => validatePublicSignals(signals, 4)).not.toThrow(); - }); - }); -}); diff --git a/tests/utils/encoding.test.ts b/tests/utils/encoding.test.ts new file mode 100644 index 0000000..001c9dc --- /dev/null +++ b/tests/utils/encoding.test.ts @@ -0,0 +1,128 @@ +import { describe, it, expect } from 'vitest'; +import { + bigIntToBytes32, + bytes32ToBigInt, + u64ToFieldStr, + hexSignalToBigInt, + bigIntToHex, +} from '../../src/utils/encoding'; + +describe('bigIntToBytes32', () => { + it('encodes 0n as 32 zero bytes', () => { + const result = bigIntToBytes32(0n); + expect(result).toHaveLength(32); + expect(result.every(b => b === 0)).toBe(true); + }); + + it('encodes 1n with last byte = 1 (big-endian)', () => { + const result = bigIntToBytes32(1n); + expect(result[31]).toBe(1); + expect(result.slice(0, 31).every(b => b === 0)).toBe(true); + }); + + it('encodes 256n correctly', () => { + const result = bigIntToBytes32(256n); + expect(result[30]).toBe(1); + expect(result[31]).toBe(0); + }); + + it('encodes max 32-byte value', () => { + const max = (1n << 256n) - 1n; + const result = bigIntToBytes32(max); + expect(result.every(b => b === 0xff)).toBe(true); + }); + + it('is inverse of bytes32ToBigInt', () => { + const original = 123456789012345678901234567890n; + expect(bytes32ToBigInt(bigIntToBytes32(original))).toBe(original); + }); +}); + +describe('bytes32ToBigInt', () => { + it('converts 32 zero bytes to 0n', () => { + expect(bytes32ToBigInt(new Uint8Array(32))).toBe(0n); + }); + + it('converts [0..0, 1] to 1n (big-endian)', () => { + const buf = new Uint8Array(32); + buf[31] = 1; + expect(bytes32ToBigInt(buf)).toBe(1n); + }); + + it('converts [0..0, 1, 0] to 256n', () => { + const buf = new Uint8Array(32); + buf[30] = 1; + expect(bytes32ToBigInt(buf)).toBe(256n); + }); + + it('is inverse of bigIntToBytes32', () => { + const original = 987654321987654321n; + expect(bytes32ToBigInt(bigIntToBytes32(original))).toBe(original); + }); +}); + +describe('u64ToFieldStr', () => { + it('returns decimal string for 0', () => { + expect(u64ToFieldStr(0n)).toBe('0'); + }); + + it('returns decimal string for max u64', () => { + const maxU64 = 18446744073709551615n; + expect(u64ToFieldStr(maxU64)).toBe('18446744073709551615'); + }); + + it('returns decimal string for arbitrary value', () => { + expect(u64ToFieldStr(42n)).toBe('42'); + }); +}); + +describe('hexSignalToBigInt', () => { + it('parses a little-endian 0x-prefixed hex signal', () => { + // 0x0100...00 in LE = 1 in BE + const leHex = '0x' + '01' + '00'.repeat(31); + expect(hexSignalToBigInt(leHex)).toBe(1n); + }); + + it('handles hex without 0x prefix', () => { + const leHex = '01' + '00'.repeat(31); + expect(hexSignalToBigInt(leHex)).toBe(1n); + }); + + it('handles 0x-uppercase prefix', () => { + const leHex = '0X' + '01' + '00'.repeat(31); + expect(hexSignalToBigInt(leHex)).toBe(1n); + }); + + it('returns 0n for all-zero signal', () => { + expect(hexSignalToBigInt('0x' + '00'.repeat(32))).toBe(0n); + }); + + it('round-trips with bigIntToBytes32 via formatPublicSignalsArray pattern', () => { + // bigIntToBytes32 produces big-endian; hexSignalToBigInt expects little-endian + // so round-trip is not direct — test the documented semantics instead + const value = 255n; + // In LE hex: last byte is MSB → '0xff' is the last 2 chars + const leHex = '0x' + 'FF' + '00'.repeat(31); + // reversed LE→BE: 0x00...00FF = 255 + expect(hexSignalToBigInt(leHex)).toBe(255n); + }); +}); + +describe('bigIntToHex', () => { + it('encodes 0n as 0x with 64 zeros', () => { + expect(bigIntToHex(0n)).toBe('0x' + '0'.repeat(64)); + }); + + it('encodes 1n correctly', () => { + expect(bigIntToHex(1n)).toBe('0x' + '0'.repeat(63) + '1'); + }); + + it('encodes 255n correctly', () => { + expect(bigIntToHex(255n)).toBe('0x' + '0'.repeat(62) + 'ff'); + }); + + it('always produces 0x-prefixed 66-char string', () => { + const result = bigIntToHex(12345678901234567890n); + expect(result).toMatch(/^0x[0-9a-f]{64}$/); + }); +}); diff --git a/tests/utils/formatting.test.ts b/tests/utils/formatting.test.ts new file mode 100644 index 0000000..9ef19d0 --- /dev/null +++ b/tests/utils/formatting.test.ts @@ -0,0 +1,112 @@ +import { describe, it, expect } from 'vitest'; +import { + normalizeProofHex, + formatProofHexForDisplay, + formatPublicSignalsArray, +} from '../../src/utils/formatting'; + +const BN254_PRIME = BigInt( + '21888242871839275222246405745257275088696311157297823662689037894645226208583' +); + +describe('normalizeProofHex', () => { + it('adds 0x prefix when missing', () => { + expect(normalizeProofHex('deadbeef')).toBe('0xdeadbeef'); + }); + + it('preserves existing 0x prefix', () => { + expect(normalizeProofHex('0xdeadbeef')).toBe('0xdeadbeef'); + }); + + it('lowercases hex characters', () => { + expect(normalizeProofHex('0xDEADBEEF')).toBe('0xdeadbeef'); + }); + + it('lowercases and adds prefix together', () => { + expect(normalizeProofHex('ABCDEF')).toBe('0xabcdef'); + }); +}); + +describe('formatProofHexForDisplay', () => { + it('returns full string when shorter than maxLength', () => { + expect(formatProofHexForDisplay('abc', 10)).toBe('abc'); + }); + + it('returns full string when equal to maxLength', () => { + const str = 'a'.repeat(10); + expect(formatProofHexForDisplay(str, 10)).toBe(str); + }); + + it('truncates with ... when longer than maxLength', () => { + const str = '0x' + 'a'.repeat(100); + const result = formatProofHexForDisplay(str, 20); + expect(result).toContain('...'); + expect(result.length).toBeLessThan(str.length); + }); + + it('uses default maxLength of 32', () => { + const str = 'a'.repeat(40); + const result = formatProofHexForDisplay(str); + expect(result).toContain('...'); + }); + + it('keeps first and last half-length characters', () => { + const str = 'AAAAABBBBB'; // 10 chars + const result = formatProofHexForDisplay(str, 4); // halfLen = 2 + expect(result).toBe('AA...BB'); + }); +}); + +describe('formatPublicSignalsArray', () => { + it('converts decimal string to 32-byte LE hex', () => { + // value = 1 → LE hex = 01 followed by 31 zero bytes + const result = formatPublicSignalsArray(['1']); + expect(result).toHaveLength(1); + expect(result[0]).toMatch(/^0x/); + expect(result[0]).toHaveLength(66); // 0x + 64 hex chars + }); + + it('converts 0 to all-zero hex', () => { + const [result] = formatPublicSignalsArray([0]); + expect(result).toBe('0x' + '00'.repeat(32)); + }); + + it('accepts bigint input', () => { + const [result] = formatPublicSignalsArray([1n]); + expect(result).toMatch(/^0x[0-9a-f]{64}$/); + }); + + it('accepts number input', () => { + const [result] = formatPublicSignalsArray([255]); + expect(result).toMatch(/^0x[0-9a-f]{64}$/); + }); + + it('converts value 1 to little-endian: first byte is 01, rest are 00', () => { + const [result] = formatPublicSignalsArray(['1']); + // LE: byte[0] = 0x01, bytes[1..31] = 0x00 + expect(result.slice(2, 4)).toBe('01'); // first byte + expect(result.slice(4)).toBe('00'.repeat(31)); // remaining bytes + }); + + it('converts value 256 to little-endian: bytes [00, 01, 00...]', () => { + const [result] = formatPublicSignalsArray(['256']); + expect(result.slice(2, 4)).toBe('00'); // byte 0 + expect(result.slice(4, 6)).toBe('01'); // byte 1 + expect(result.slice(6)).toBe('00'.repeat(30)); + }); + + it('processes multiple signals', () => { + const result = formatPublicSignalsArray(['1', '2', '3']); + expect(result).toHaveLength(3); + result.forEach(s => expect(s).toMatch(/^0x[0-9a-f]{64}$/)); + }); + + it('throws when value is negative', () => { + expect(() => formatPublicSignalsArray(['-1'])).toThrow(); + }); + + it('throws when value exceeds BN254 prime', () => { + const tooBig = BN254_PRIME.toString(); + expect(() => formatPublicSignalsArray([tooBig])).toThrow('out of BN254 field range'); + }); +}); diff --git a/tests/utils/validation.test.ts b/tests/utils/validation.test.ts new file mode 100644 index 0000000..2916198 --- /dev/null +++ b/tests/utils/validation.test.ts @@ -0,0 +1,90 @@ +import { describe, it, expect } from 'vitest'; +import { + validateInputs, + validatePublicSignals, + validateProofSize, +} from '../../src/utils/validation'; + +describe('validateInputs', () => { + it('passes for a valid inputs object', () => { + expect(() => validateInputs({ a: '1', b: '2' })).not.toThrow(); + }); + + it('throws when inputs is null', () => { + expect(() => validateInputs(null as any)).toThrow('Inputs must be an object'); + }); + + it('throws when inputs is not an object', () => { + expect(() => validateInputs('string' as any)).toThrow('Inputs must be an object'); + expect(() => validateInputs(42 as any)).toThrow('Inputs must be an object'); + }); + + it('throws when a field is undefined', () => { + expect(() => validateInputs({ a: undefined })).toThrow('"a" is undefined or null'); + }); + + it('throws when a field is null', () => { + expect(() => validateInputs({ commitment: null })).toThrow('"commitment" is undefined or null'); + }); + + it('passes for numeric and array values', () => { + expect(() => + validateInputs({ scalar: 1, array: ['1', '2'], nested: [['1'], ['2']] }) + ).not.toThrow(); + }); + + it('passes for empty object', () => { + expect(() => validateInputs({})).not.toThrow(); + }); +}); + +describe('validatePublicSignals', () => { + it('passes when count matches expected', () => { + expect(() => validatePublicSignals(['a', 'b', 'c'], 3)).not.toThrow(); + }); + + it('throws when count is too low', () => { + expect(() => validatePublicSignals(['a'], 3)).toThrow( + 'Invalid public signals count: expected 3, got 1' + ); + }); + + it('throws when count is too high', () => { + expect(() => validatePublicSignals(['a', 'b', 'c', 'd'], 3)).toThrow( + 'Invalid public signals count: expected 3, got 4' + ); + }); + + it('passes for empty signals when expected is 0', () => { + expect(() => validatePublicSignals([], 0)).not.toThrow(); + }); +}); + +describe('validateProofSize', () => { + const validProof = '0x' + 'ab'.repeat(128); // 256 hex chars = 128 bytes + + it('passes for a valid 128-byte proof (with 0x prefix)', () => { + expect(() => validateProofSize(validProof)).not.toThrow(); + }); + + it('passes for a valid 128-byte proof (without 0x prefix)', () => { + expect(() => validateProofSize('ab'.repeat(128))).not.toThrow(); + }); + + it('throws when proof is too short', () => { + expect(() => validateProofSize('0x' + 'ab'.repeat(64))).toThrow('Invalid proof size'); + }); + + it('throws when proof is too long', () => { + expect(() => validateProofSize('0x' + 'ab'.repeat(200))).toThrow('Invalid proof size'); + }); + + it('throws for empty string', () => { + expect(() => validateProofSize('')).toThrow('Invalid proof size'); + }); + + it('includes expected and actual length in error message', () => { + const shortProof = '0xabcd'; // 2 bytes + expect(() => validateProofSize(shortProof)).toThrow('expected 256 hex chars'); + }); +}); diff --git a/tests/wasm/loader.test.ts b/tests/wasm/loader.test.ts new file mode 100644 index 0000000..70ce8e0 --- /dev/null +++ b/tests/wasm/loader.test.ts @@ -0,0 +1,157 @@ +/** + * Tests: wasm/loader.ts + * + * The actual WASM init requires @orbinum/groth16-proofs binary to be present. + * We mock the module to test the loader logic in isolation. + */ + +import { describe, it, expect, vi, beforeEach } from 'vitest'; + +// ─── Mock @orbinum/groth16-proofs before importing loader ──────────────────── + +vi.mock('@orbinum/groth16-proofs', () => ({ + default: vi.fn().mockResolvedValue(undefined), + init_panic_hook: vi.fn(), + compress_snarkjs_proof_wasm: vi.fn().mockReturnValue('0x' + 'ab'.repeat(128)), + generate_proof_from_decimal_wasm: vi.fn().mockReturnValue( + JSON.stringify({ + proof: '0x' + 'cd'.repeat(128), + publicSignals: ['0x' + '01'.repeat(32), '0x' + '02'.repeat(32)], + }) + ), + initSync: vi.fn(), +})); + +// Import after mock is set up +import { + initWasm, + compressSnarkjsProofWasm, + generateProofFromWitnessWasm, +} from '../../src/wasm/loader'; + +// ─── Tests ──────────────────────────────────────────────────────────────────── + +describe('initWasm', () => { + it('initializes without throwing', async () => { + await expect(initWasm()).resolves.toBeUndefined(); + }); + + it('is idempotent — calling twice does not throw', async () => { + await initWasm(); + await expect(initWasm()).resolves.toBeUndefined(); + }); +}); + +describe('compressSnarkjsProofWasm', () => { + const validProof = { + pi_a: ['1', '2', '1'], + pi_b: [ + ['3', '4'], + ['5', '6'], + ], + pi_c: ['7', '8', '1'], + }; + + it('returns a 0x-prefixed hex string', async () => { + const result = await compressSnarkjsProofWasm(validProof); + expect(result).toMatch(/^0x[0-9a-f]+$/i); + }); + + it('calls the WASM compress function with serialized JSON', async () => { + const wasm = await import('@orbinum/groth16-proofs'); + vi.mocked(wasm.compress_snarkjs_proof_wasm).mockClear(); + + await compressSnarkjsProofWasm(validProof); + + expect(wasm.compress_snarkjs_proof_wasm).toHaveBeenCalledTimes(1); + const arg = (wasm.compress_snarkjs_proof_wasm as ReturnType).mock.calls[0][0]; + const parsed = JSON.parse(arg); + expect(parsed).toHaveProperty('pi_a'); + expect(parsed).toHaveProperty('pi_b'); + expect(parsed).toHaveProperty('pi_c'); + }); + + it('normalizes numeric pi_a fields to strings', async () => { + const wasm = await import('@orbinum/groth16-proofs'); + vi.mocked(wasm.compress_snarkjs_proof_wasm).mockClear(); + + const proofWithNumbers = { + pi_a: [1, 2, 1] as any, + pi_b: [ + [3, 4], + [5, 6], + ] as any, + pi_c: [7, 8, 1] as any, + }; + + await compressSnarkjsProofWasm(proofWithNumbers); + + const arg = (wasm.compress_snarkjs_proof_wasm as ReturnType).mock.calls[0][0]; + const parsed = JSON.parse(arg); + expect(typeof parsed.pi_a[0]).toBe('string'); + expect(typeof parsed.pi_c[0]).toBe('string'); + }); + + it('throws when WASM compress function throws', async () => { + const wasm = await import('@orbinum/groth16-proofs'); + vi.mocked(wasm.compress_snarkjs_proof_wasm).mockImplementationOnce(() => { + throw new Error('invalid G1 point'); + }); + + await expect(compressSnarkjsProofWasm(validProof)).rejects.toThrow( + 'WASM proof compression failed: invalid G1 point' + ); + }); +}); + +// ─── generateProofFromWitnessWasm ──────────────────────────────────────────── + +describe('generateProofFromWitnessWasm', () => { + const witnessJson = JSON.stringify(['1', '12345', '67890', '111']); + const provingKeyBytes = new Uint8Array([1, 2, 3, 4]); + + it('returns proof and publicSignals from WASM output', async () => { + const result = await generateProofFromWitnessWasm(2, witnessJson, provingKeyBytes); + + expect(result).toHaveProperty('proof'); + expect(result).toHaveProperty('publicSignals'); + expect(result.proof).toMatch(/^0x[0-9a-f]+$/i); + expect(Array.isArray(result.publicSignals)).toBe(true); + expect(result.publicSignals).toHaveLength(2); + }); + + it('calls generate_proof_from_decimal_wasm with correct arguments', async () => { + const wasm = await import('@orbinum/groth16-proofs'); + vi.mocked(wasm.generate_proof_from_decimal_wasm).mockClear(); + + await generateProofFromWitnessWasm(2, witnessJson, provingKeyBytes); + + expect(wasm.generate_proof_from_decimal_wasm).toHaveBeenCalledTimes(1); + const [numSigs, wtns, pkBytes] = ( + wasm.generate_proof_from_decimal_wasm as ReturnType + ).mock.calls[0]; + expect(numSigs).toBe(2); + expect(wtns).toBe(witnessJson); + expect(pkBytes).toBe(provingKeyBytes); + }); + + it('throws when WASM function throws', async () => { + const wasm = await import('@orbinum/groth16-proofs'); + vi.mocked(wasm.generate_proof_from_decimal_wasm).mockImplementationOnce(() => { + throw new Error('deserialize error'); + }); + + await expect(generateProofFromWitnessWasm(2, witnessJson, provingKeyBytes)).rejects.toThrow( + 'WASM proof generation failed: deserialize error' + ); + }); + + it('throws when WASM returns invalid JSON', async () => { + const wasm = await import('@orbinum/groth16-proofs'); + vi.mocked(wasm.generate_proof_from_decimal_wasm).mockReturnValueOnce('not-json{{'); + + await expect(generateProofFromWitnessWasm(2, witnessJson, provingKeyBytes)).rejects.toThrow( + 'Failed to parse WASM proof output' + ); + }); +}); diff --git a/tsconfig.json b/tsconfig.json index 0ae30bc..3b4dc87 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,18 +1,21 @@ { "compilerOptions": { - "target": "ES2020", - "module": "commonjs", - "lib": ["ES2020", "dom"], - "declaration": true, - "outDir": "./dist", - "rootDir": "./src", + "target": "ES2022", + "module": "CommonJS", + "moduleResolution": "node", + "ignoreDeprecations": "6.0", + "lib": ["ES2022", "dom"], + "outDir": "dist", + "rootDir": "src", "strict": true, "esModuleInterop": true, "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, - "moduleResolution": "node" + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "types": ["node"] }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist", "tests"] + "include": ["src"], + "exclude": ["node_modules", "dist"] } diff --git a/tsconfig.test.json b/tsconfig.test.json index 63da8b0..468852c 100644 --- a/tsconfig.test.json +++ b/tsconfig.test.json @@ -1,12 +1,10 @@ { "extends": "./tsconfig.json", "compilerOptions": { - "target": "ES2020", - "module": "commonjs", "noEmit": true, "rootDir": ".", - "skipLibCheck": true + "types": ["vitest/globals", "node"] }, - "include": ["tests/**/*", "src/**/*"], + "include": ["src/**/*", "tests/**/*"], "exclude": ["node_modules", "dist"] } diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..383b71b --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: true, + environment: 'node', + include: ['tests/**/*.test.ts'], + coverage: { + provider: 'v8', + include: ['src/**/*.ts'], + exclude: ['src/**/*.d.ts', 'src/index.ts'], + }, + testTimeout: 30000, + }, +}); From 4ff74e9e483bfd835779886780c31ee1cbfb492b Mon Sep 17 00:00:00 2001 From: nol4lej Date: Wed, 8 Apr 2026 12:12:50 -0400 Subject: [PATCH 2/3] ci: migrate workflows from npm to pnpm --- .github/workflows/ci.yml | 32 ++++++++++++++++++++++---------- .github/workflows/release.yml | 16 ++++++++++------ 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 304ab74..65331f7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,20 +14,24 @@ jobs: - name: Checkout code uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + version: 10 + - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '22' - cache: 'npm' + cache: 'pnpm' - name: Install dependencies - run: npm ci + run: pnpm install --frozen-lockfile - name: Check TypeScript types - run: npm run lint + run: pnpm lint - name: Check code formatting - run: npm run format:check + run: pnpm format:check build-typescript: name: Build TypeScript @@ -36,17 +40,21 @@ jobs: - name: Checkout code uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + version: 10 + - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '22' - cache: 'npm' + cache: 'pnpm' - name: Install dependencies - run: npm ci + run: pnpm install --frozen-lockfile - name: Build TypeScript - run: npm run build + run: pnpm build - name: Upload TypeScript artifact uses: actions/upload-artifact@v4 @@ -63,14 +71,18 @@ jobs: - name: Checkout code uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + version: 10 + - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '22' - cache: 'npm' + cache: 'pnpm' - name: Install dependencies - run: npm ci + run: pnpm install --frozen-lockfile - name: Download TypeScript build uses: actions/download-artifact@v4 @@ -79,7 +91,7 @@ jobs: path: dist/ - name: Run tests - run: npm test + run: pnpm test all-checks: name: All Checks Passed diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 266ac88..9f70ef4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,15 +20,19 @@ jobs: with: fetch-depth: 0 + - uses: pnpm/action-setup@v4 + with: + version: 10 + - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: "22" - cache: "npm" + cache: "pnpm" registry-url: "https://registry.npmjs.org" - name: Install dependencies - run: npm ci + run: pnpm install --frozen-lockfile - name: Extract version from package.json id: version @@ -51,15 +55,15 @@ jobs: - name: Check code formatting if: steps.check_tag.outputs.exists == 'false' - run: npm run format:check + run: pnpm format:check - name: Build TypeScript if: steps.check_tag.outputs.exists == 'false' - run: npm run build + run: pnpm build - name: Run tests if: steps.check_tag.outputs.exists == 'false' - run: npm test + run: pnpm test - name: Create GitHub Release and Tag if: steps.check_tag.outputs.exists == 'false' @@ -74,6 +78,6 @@ jobs: - name: Publish to NPM if: steps.check_tag.outputs.exists == 'false' - run: npm publish --access public + run: pnpm publish --access public env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} From 0aac95439ee0aa633df30f19e0e8f346201f8d5d Mon Sep 17 00:00:00 2001 From: nol4lej Date: Wed, 8 Apr 2026 12:13:56 -0400 Subject: [PATCH 3/3] ci: remove pnpm version from action-setup, use packageManager from package.json --- .github/workflows/ci.yml | 6 ------ .github/workflows/release.yml | 2 -- 2 files changed, 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 65331f7..c825d44 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,8 +15,6 @@ jobs: uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 - with: - version: 10 - name: Setup Node.js uses: actions/setup-node@v4 @@ -41,8 +39,6 @@ jobs: uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 - with: - version: 10 - name: Setup Node.js uses: actions/setup-node@v4 @@ -72,8 +68,6 @@ jobs: uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 - with: - version: 10 - name: Setup Node.js uses: actions/setup-node@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9f70ef4..766788e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,8 +21,6 @@ jobs: fetch-depth: 0 - uses: pnpm/action-setup@v4 - with: - version: 10 - name: Setup Node.js uses: actions/setup-node@v4