@sip-protocol/sdk 0.7.2 → 0.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (262) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +267 -0
  3. package/dist/{TransportWebUSB-TQ7WZ4LE.mjs → TransportWebUSB-YQMAGJAJ.mjs} +12 -9
  4. package/dist/browser.d.mts +10 -4
  5. package/dist/browser.d.ts +10 -4
  6. package/dist/browser.js +48874 -18336
  7. package/dist/browser.mjs +674 -48
  8. package/dist/chunk-4GRJ5MAW.mjs +152 -0
  9. package/dist/chunk-5D7A3L3W.mjs +717 -0
  10. package/dist/chunk-64AYA5F5.mjs +7834 -0
  11. package/dist/chunk-GMDGB22A.mjs +379 -0
  12. package/dist/chunk-I534WKN7.mjs +328 -0
  13. package/dist/chunk-IBZVA5Y7.mjs +1003 -0
  14. package/dist/chunk-PRRZAWJE.mjs +223 -0
  15. package/dist/{chunk-UJCSKKID.mjs → chunk-XGB3TDIC.mjs} +13 -1
  16. package/dist/chunk-YWGJ77A2.mjs +33806 -0
  17. package/dist/{chunk-6WGN57S2.mjs → chunk-Z3K7W5S3.mjs} +48 -0
  18. package/dist/constants-LHAAUC2T.mjs +51 -0
  19. package/dist/dist-2OGQ7FED.mjs +3957 -0
  20. package/dist/dist-IFHPYLDX.mjs +254 -0
  21. package/dist/fulfillment_proof-ANHVPKTB.mjs +21 -0
  22. package/dist/funding_proof-ICFZ5LHY.mjs +21 -0
  23. package/dist/index-DXh2IGkz.d.ts +24681 -0
  24. package/dist/index-DeE1ZzA4.d.mts +24681 -0
  25. package/dist/index.d.mts +9 -3
  26. package/dist/index.d.ts +9 -3
  27. package/dist/index.js +48676 -17318
  28. package/dist/index.mjs +583 -19
  29. package/dist/interface-Bf7w1PLW.d.mts +679 -0
  30. package/dist/interface-Bf7w1PLW.d.ts +679 -0
  31. package/dist/{noir-DKfEzWy9.d.mts → noir-kzbLVTei.d.mts} +31 -21
  32. package/dist/{noir-DKfEzWy9.d.ts → noir-kzbLVTei.d.ts} +31 -21
  33. package/dist/proofs/halo2.d.mts +151 -0
  34. package/dist/proofs/halo2.d.ts +151 -0
  35. package/dist/proofs/halo2.js +350 -0
  36. package/dist/proofs/halo2.mjs +11 -0
  37. package/dist/proofs/kimchi.d.mts +160 -0
  38. package/dist/proofs/kimchi.d.ts +160 -0
  39. package/dist/proofs/kimchi.js +431 -0
  40. package/dist/proofs/kimchi.mjs +13 -0
  41. package/dist/proofs/noir.d.mts +1 -1
  42. package/dist/proofs/noir.d.ts +1 -1
  43. package/dist/proofs/noir.js +74 -18
  44. package/dist/proofs/noir.mjs +84 -24
  45. package/dist/solana-U3MEGU7W.mjs +280 -0
  46. package/dist/validity_proof-3POXLPNY.mjs +21 -0
  47. package/package.json +54 -21
  48. package/src/adapters/index.ts +41 -0
  49. package/src/adapters/jupiter.ts +571 -0
  50. package/src/adapters/near-intents.ts +135 -0
  51. package/src/advisor/advisor.ts +653 -0
  52. package/src/advisor/index.ts +54 -0
  53. package/src/advisor/tools.ts +303 -0
  54. package/src/advisor/types.ts +164 -0
  55. package/src/chains/ethereum/announcement.ts +536 -0
  56. package/src/chains/ethereum/bnb-optimizations.ts +474 -0
  57. package/src/chains/ethereum/commitment.ts +522 -0
  58. package/src/chains/ethereum/constants.ts +462 -0
  59. package/src/chains/ethereum/deployment.ts +596 -0
  60. package/src/chains/ethereum/gas-estimation.ts +538 -0
  61. package/src/chains/ethereum/index.ts +268 -0
  62. package/src/chains/ethereum/optimizations.ts +614 -0
  63. package/src/chains/ethereum/privacy-adapter.ts +855 -0
  64. package/src/chains/ethereum/registry.ts +584 -0
  65. package/src/chains/ethereum/rpc.ts +905 -0
  66. package/src/chains/ethereum/stealth.ts +491 -0
  67. package/src/chains/ethereum/token.ts +790 -0
  68. package/src/chains/ethereum/transfer.ts +637 -0
  69. package/src/chains/ethereum/types.ts +456 -0
  70. package/src/chains/ethereum/viewing-key.ts +455 -0
  71. package/src/chains/near/commitment.ts +608 -0
  72. package/src/chains/near/constants.ts +284 -0
  73. package/src/chains/near/function-call.ts +871 -0
  74. package/src/chains/near/history.ts +654 -0
  75. package/src/chains/near/implicit-account.ts +840 -0
  76. package/src/chains/near/index.ts +393 -0
  77. package/src/chains/near/native-transfer.ts +658 -0
  78. package/src/chains/near/nep141.ts +775 -0
  79. package/src/chains/near/privacy-adapter.ts +889 -0
  80. package/src/chains/near/resolver.ts +971 -0
  81. package/src/chains/near/rpc.ts +1016 -0
  82. package/src/chains/near/stealth.ts +419 -0
  83. package/src/chains/near/types.ts +317 -0
  84. package/src/chains/near/viewing-key.ts +876 -0
  85. package/src/chains/solana/anchor-transfer.ts +386 -0
  86. package/src/chains/solana/commitment.ts +577 -0
  87. package/src/chains/solana/constants.ts +126 -12
  88. package/src/chains/solana/ephemeral-keys.ts +543 -0
  89. package/src/chains/solana/index.ts +276 -1
  90. package/src/chains/solana/key-derivation.ts +418 -0
  91. package/src/chains/solana/kit-compat.ts +334 -0
  92. package/src/chains/solana/optimizations.ts +560 -0
  93. package/src/chains/solana/privacy-adapter.ts +605 -0
  94. package/src/chains/solana/providers/generic.ts +201 -0
  95. package/src/chains/solana/providers/helius-enhanced-types.ts +336 -0
  96. package/src/chains/solana/providers/helius-enhanced.ts +623 -0
  97. package/src/chains/solana/providers/helius.ts +402 -0
  98. package/src/chains/solana/providers/index.ts +85 -0
  99. package/src/chains/solana/providers/interface.ts +221 -0
  100. package/src/chains/solana/providers/quicknode.ts +409 -0
  101. package/src/chains/solana/providers/triton.ts +426 -0
  102. package/src/chains/solana/providers/webhook.ts +790 -0
  103. package/src/chains/solana/rpc-client.ts +1150 -0
  104. package/src/chains/solana/scan.ts +170 -73
  105. package/src/chains/solana/sol-transfer.ts +732 -0
  106. package/src/chains/solana/spl-transfer.ts +886 -0
  107. package/src/chains/solana/stealth-scanner.ts +703 -0
  108. package/src/chains/solana/sunspot-verifier.ts +453 -0
  109. package/src/chains/solana/transaction-builder.ts +755 -0
  110. package/src/chains/solana/transfer.ts +74 -5
  111. package/src/chains/solana/types.ts +77 -7
  112. package/src/chains/solana/utils.ts +110 -0
  113. package/src/chains/solana/viewing-key.ts +807 -0
  114. package/src/compliance/fireblocks.ts +921 -0
  115. package/src/compliance/index.ts +37 -0
  116. package/src/compliance/range-sas.ts +956 -0
  117. package/src/config/endpoints.ts +100 -0
  118. package/src/crypto.ts +11 -8
  119. package/src/errors.ts +82 -0
  120. package/src/evm/erc4337-relayer.ts +830 -0
  121. package/src/evm/index.ts +47 -0
  122. package/src/fees/calculator.ts +396 -0
  123. package/src/fees/index.ts +87 -0
  124. package/src/fees/near-contract.ts +429 -0
  125. package/src/fees/types.ts +268 -0
  126. package/src/index.ts +785 -1
  127. package/src/intent.ts +6 -3
  128. package/src/logger.ts +324 -0
  129. package/src/network/index.ts +80 -0
  130. package/src/network/proxy.ts +691 -0
  131. package/src/optimizations/index.ts +541 -0
  132. package/src/oracle/types.ts +1 -0
  133. package/src/privacy-backends/arcium-types.ts +727 -0
  134. package/src/privacy-backends/arcium.ts +719 -0
  135. package/src/privacy-backends/combined-privacy.ts +866 -0
  136. package/src/privacy-backends/cspl-token.ts +595 -0
  137. package/src/privacy-backends/cspl-types.ts +512 -0
  138. package/src/privacy-backends/cspl.ts +907 -0
  139. package/src/privacy-backends/health.ts +488 -0
  140. package/src/privacy-backends/inco-types.ts +323 -0
  141. package/src/privacy-backends/inco.ts +616 -0
  142. package/src/privacy-backends/index.ts +336 -0
  143. package/src/privacy-backends/interface.ts +906 -0
  144. package/src/privacy-backends/lru-cache.ts +343 -0
  145. package/src/privacy-backends/magicblock.ts +458 -0
  146. package/src/privacy-backends/mock.ts +258 -0
  147. package/src/privacy-backends/privacycash-types.ts +278 -0
  148. package/src/privacy-backends/privacycash.ts +456 -0
  149. package/src/privacy-backends/private-swap.ts +570 -0
  150. package/src/privacy-backends/rate-limiter.ts +683 -0
  151. package/src/privacy-backends/registry.ts +690 -0
  152. package/src/privacy-backends/router.ts +626 -0
  153. package/src/privacy-backends/shadowwire.ts +449 -0
  154. package/src/privacy-backends/sip-native.ts +256 -0
  155. package/src/privacy-logger.ts +191 -0
  156. package/src/production-safety.ts +373 -0
  157. package/src/proofs/aggregator.ts +1029 -0
  158. package/src/proofs/browser-composer.ts +1150 -0
  159. package/src/proofs/browser.ts +113 -25
  160. package/src/proofs/cache/index.ts +127 -0
  161. package/src/proofs/cache/interface.ts +545 -0
  162. package/src/proofs/cache/key-generator.ts +188 -0
  163. package/src/proofs/cache/lru-cache.ts +481 -0
  164. package/src/proofs/cache/multi-tier-cache.ts +575 -0
  165. package/src/proofs/cache/persistent-cache.ts +788 -0
  166. package/src/proofs/compliance-proof.ts +872 -0
  167. package/src/proofs/composer/base.ts +923 -0
  168. package/src/proofs/composer/index.ts +25 -0
  169. package/src/proofs/composer/interface.ts +518 -0
  170. package/src/proofs/composer/types.ts +383 -0
  171. package/src/proofs/converters/halo2.ts +452 -0
  172. package/src/proofs/converters/index.ts +208 -0
  173. package/src/proofs/converters/interface.ts +363 -0
  174. package/src/proofs/converters/kimchi.ts +462 -0
  175. package/src/proofs/converters/noir.ts +451 -0
  176. package/src/proofs/fallback.ts +888 -0
  177. package/src/proofs/halo2.ts +42 -0
  178. package/src/proofs/index.ts +471 -0
  179. package/src/proofs/interface.ts +13 -0
  180. package/src/proofs/kimchi.ts +42 -0
  181. package/src/proofs/lazy.ts +1004 -0
  182. package/src/proofs/mock.ts +25 -1
  183. package/src/proofs/noir.ts +111 -30
  184. package/src/proofs/orchestrator.ts +960 -0
  185. package/src/proofs/parallel/concurrency.ts +297 -0
  186. package/src/proofs/parallel/dependency-graph.ts +602 -0
  187. package/src/proofs/parallel/executor.ts +420 -0
  188. package/src/proofs/parallel/index.ts +131 -0
  189. package/src/proofs/parallel/interface.ts +685 -0
  190. package/src/proofs/parallel/worker-pool.ts +644 -0
  191. package/src/proofs/providers/halo2.ts +560 -0
  192. package/src/proofs/providers/index.ts +34 -0
  193. package/src/proofs/providers/kimchi.ts +641 -0
  194. package/src/proofs/validator.ts +881 -0
  195. package/src/proofs/verifier.ts +867 -0
  196. package/src/quantum/index.ts +112 -0
  197. package/src/quantum/winternitz-vault.ts +639 -0
  198. package/src/quantum/wots.ts +611 -0
  199. package/src/settlement/backends/direct-chain.ts +1 -0
  200. package/src/settlement/index.ts +9 -0
  201. package/src/settlement/router.ts +732 -46
  202. package/src/solana/index.ts +72 -0
  203. package/src/solana/jito-relayer.ts +687 -0
  204. package/src/solana/noir-verifier-types.ts +430 -0
  205. package/src/solana/noir-verifier.ts +816 -0
  206. package/src/stealth/address-derivation.ts +193 -0
  207. package/src/stealth/ed25519.ts +431 -0
  208. package/src/stealth/index.ts +233 -0
  209. package/src/stealth/meta-address.ts +221 -0
  210. package/src/stealth/secp256k1.ts +368 -0
  211. package/src/stealth/utils.ts +194 -0
  212. package/src/stealth.ts +50 -1504
  213. package/src/surveillance/algorithms/address-reuse.ts +143 -0
  214. package/src/surveillance/algorithms/cluster.ts +247 -0
  215. package/src/surveillance/algorithms/exchange.ts +295 -0
  216. package/src/surveillance/algorithms/temporal.ts +337 -0
  217. package/src/surveillance/analyzer.ts +442 -0
  218. package/src/surveillance/index.ts +64 -0
  219. package/src/surveillance/scoring.ts +372 -0
  220. package/src/surveillance/types.ts +264 -0
  221. package/src/sync/index.ts +106 -0
  222. package/src/sync/manager.ts +504 -0
  223. package/src/sync/mock-provider.ts +318 -0
  224. package/src/sync/oblivious.ts +625 -0
  225. package/src/tokens/index.ts +15 -0
  226. package/src/tokens/registry.ts +301 -0
  227. package/src/utils/deprecation.ts +94 -0
  228. package/src/utils/index.ts +9 -0
  229. package/src/wallet/ethereum/index.ts +68 -0
  230. package/src/wallet/ethereum/metamask-privacy.ts +420 -0
  231. package/src/wallet/ethereum/multi-wallet.ts +646 -0
  232. package/src/wallet/ethereum/privacy-adapter.ts +700 -0
  233. package/src/wallet/ethereum/types.ts +3 -1
  234. package/src/wallet/ethereum/walletconnect-adapter.ts +675 -0
  235. package/src/wallet/hardware/index.ts +10 -0
  236. package/src/wallet/hardware/ledger-privacy.ts +414 -0
  237. package/src/wallet/index.ts +71 -0
  238. package/src/wallet/near/adapter.ts +626 -0
  239. package/src/wallet/near/index.ts +86 -0
  240. package/src/wallet/near/meteor-wallet.ts +1153 -0
  241. package/src/wallet/near/my-near-wallet.ts +790 -0
  242. package/src/wallet/near/wallet-selector.ts +702 -0
  243. package/src/wallet/solana/adapter.ts +6 -4
  244. package/src/wallet/solana/index.ts +13 -0
  245. package/src/wallet/solana/privacy-adapter.ts +567 -0
  246. package/src/wallet/sui/types.ts +6 -4
  247. package/src/zcash/rpc-client.ts +13 -6
  248. package/dist/chunk-3INS3PR5.mjs +0 -884
  249. package/dist/chunk-3OVABDRH.mjs +0 -17096
  250. package/dist/chunk-DLDWZFYC.mjs +0 -1495
  251. package/dist/chunk-E6SZWREQ.mjs +0 -57
  252. package/dist/chunk-G33LB27A.mjs +0 -16166
  253. package/dist/chunk-HGU6HZRC.mjs +0 -231
  254. package/dist/chunk-L2K34JCU.mjs +0 -1496
  255. package/dist/chunk-SN4ZDTVW.mjs +0 -16166
  256. package/dist/constants-VOI7BSLK.mjs +0 -27
  257. package/dist/index-BYZbDjal.d.ts +0 -11390
  258. package/dist/index-CHB3KuOB.d.mts +0 -11859
  259. package/dist/index-CzWPI6Le.d.ts +0 -11859
  260. package/dist/index-xbWjohNq.d.mts +0 -11390
  261. package/dist/solana-5EMCTPTS.mjs +0 -46
  262. package/dist/solana-Q4NAVBTS.mjs +0 -46
@@ -0,0 +1,1150 @@
1
+ /**
2
+ * Browser-Compatible Proof Composer
3
+ *
4
+ * Provides proof composition capabilities optimized for browser environments.
5
+ * Handles WASM loading, Web Workers, memory limits, and progress reporting.
6
+ *
7
+ * @module proofs/browser-composer
8
+ * @see https://github.com/sip-protocol/sip-protocol/issues/346
9
+ *
10
+ * M20-19: Browser-compatible proof composition
11
+ */
12
+
13
+ import type {
14
+ ProofSystem,
15
+ ProofAggregationStrategy,
16
+ SingleProof,
17
+ ComposedProof,
18
+ ProofCompositionConfig,
19
+ CompositionResult,
20
+ VerificationResult,
21
+ CompositionEventListener,
22
+ } from '@sip-protocol/types'
23
+
24
+ import {
25
+ ProofAggregationStrategy as Strategy,
26
+ ComposedProofStatus,
27
+ DEFAULT_COMPOSITION_CONFIG,
28
+ } from '@sip-protocol/types'
29
+
30
+ import type {
31
+ ProofComposer,
32
+ ComposableProofProvider,
33
+ } from './composer/interface'
34
+
35
+ import {
36
+ ProofCompositionError,
37
+ CompositionTimeoutError,
38
+ } from './composer/interface'
39
+
40
+ import type {
41
+ ProofProviderRegistration,
42
+ RegisterProviderOptions,
43
+ ProofGenerationRequest,
44
+ ProofGenerationResult,
45
+ ComposeProofsOptions,
46
+ VerifyComposedProofOptions,
47
+ AggregateProofsOptions,
48
+ AggregationResult,
49
+ ConvertProofOptions,
50
+ ConversionResult,
51
+ CacheStats,
52
+ WorkerPoolStatus,
53
+ CompatibilityMatrix,
54
+ FallbackConfig,
55
+ TelemetryCollector,
56
+ } from './composer/types'
57
+
58
+ import { BaseProofComposer } from './composer/base'
59
+
60
+ import {
61
+ isBrowser,
62
+ supportsWebWorkers,
63
+ getMobileDeviceInfo,
64
+ checkMobileWASMCompatibility,
65
+ createWorkerBlobUrl,
66
+ revokeWorkerBlobUrl,
67
+ estimateAvailableMemory,
68
+ } from './browser-utils'
69
+
70
+ import type { MobileDeviceInfo, MobileWASMCompatibility } from './browser-utils'
71
+
72
+ // ─── Types ──────────────────────────────────────────────────────────────────
73
+
74
+ /**
75
+ * Browser proof composer configuration
76
+ */
77
+ export interface BrowserProofComposerConfig extends Partial<ProofCompositionConfig> {
78
+ /**
79
+ * Enable Web Worker for proof composition
80
+ * @default true
81
+ */
82
+ useWorker?: boolean
83
+
84
+ /**
85
+ * Enable verbose logging
86
+ * @default false
87
+ */
88
+ verbose?: boolean
89
+
90
+ /**
91
+ * Maximum memory limit in bytes (auto-detected if not set)
92
+ */
93
+ maxMemoryBytes?: number
94
+
95
+ /**
96
+ * Chunk size for processing large proof sets
97
+ * @default 5
98
+ */
99
+ chunkSize?: number
100
+
101
+ /**
102
+ * Enable progress reporting via MessageChannel
103
+ * @default true
104
+ */
105
+ enableProgressReporting?: boolean
106
+
107
+ /**
108
+ * Timeout for worker initialization (ms)
109
+ * @default 30000
110
+ */
111
+ workerInitTimeoutMs?: number
112
+
113
+ /**
114
+ * Allow initialization on devices with poor compatibility
115
+ * @default false
116
+ */
117
+ forceInitialize?: boolean
118
+
119
+ /**
120
+ * Mobile-optimized mode (auto-detected)
121
+ */
122
+ mobileMode?: boolean
123
+ }
124
+
125
+ /**
126
+ * Progress event for composition operations
127
+ */
128
+ export interface CompositionProgress {
129
+ /** Current stage */
130
+ stage: 'initializing' | 'validating' | 'processing' | 'aggregating' | 'verifying' | 'complete'
131
+ /** Progress percentage (0-100) */
132
+ percent: number
133
+ /** Human-readable message */
134
+ message: string
135
+ /** Current proof index (if applicable) */
136
+ currentProof?: number
137
+ /** Total proofs (if applicable) */
138
+ totalProofs?: number
139
+ /** Current chunk (if processing in chunks) */
140
+ currentChunk?: number
141
+ /** Total chunks */
142
+ totalChunks?: number
143
+ }
144
+
145
+ /**
146
+ * Progress callback type
147
+ */
148
+ export type CompositionProgressCallback = (progress: CompositionProgress) => void
149
+
150
+ /**
151
+ * Extended compose options with browser-specific progress callback.
152
+ * Use composeWithProgress() for this type, or compose() for standard interface.
153
+ */
154
+ export interface BrowserComposeOptions {
155
+ /** Proofs to compose */
156
+ proofs: SingleProof[]
157
+ /** Aggregation strategy */
158
+ strategy?: ProofAggregationStrategy
159
+ /** Configuration overrides */
160
+ config?: Partial<ProofCompositionConfig>
161
+ /** Abort signal for cancellation */
162
+ abortSignal?: AbortSignal
163
+ /** Progress callback for UI updates */
164
+ onProgress?: CompositionProgressCallback
165
+ }
166
+
167
+ /**
168
+ * Worker message types
169
+ */
170
+ type WorkerMessageType =
171
+ | 'init'
172
+ | 'compose'
173
+ | 'verify'
174
+ | 'cancel'
175
+ | 'dispose'
176
+
177
+ /**
178
+ * Worker request message
179
+ */
180
+ interface WorkerRequest {
181
+ id: string
182
+ type: WorkerMessageType
183
+ payload?: unknown
184
+ }
185
+
186
+ /**
187
+ * Worker response message
188
+ */
189
+ interface WorkerResponse {
190
+ id: string
191
+ type: 'success' | 'error' | 'progress'
192
+ result?: unknown
193
+ error?: string
194
+ progress?: CompositionProgress
195
+ }
196
+
197
+ // ─── Browser Proof Composer ─────────────────────────────────────────────────
198
+
199
+ /**
200
+ * Browser-compatible proof composer.
201
+ *
202
+ * Wraps BaseProofComposer with browser-specific optimizations:
203
+ * - Web Worker support for non-blocking UI
204
+ * - SharedArrayBuffer fallback handling
205
+ * - Memory limit management
206
+ * - Chunked processing for large proof sets
207
+ * - Progress reporting via MessageChannel
208
+ * - Mobile device optimization
209
+ *
210
+ * @example
211
+ * ```typescript
212
+ * const composer = new BrowserProofComposer({ verbose: true })
213
+ *
214
+ * // Check browser compatibility
215
+ * const compat = BrowserProofComposer.checkCompatibility()
216
+ * if (compat.score < 70) {
217
+ * console.warn('Limited browser support:', compat.issues)
218
+ * }
219
+ *
220
+ * // Initialize
221
+ * await composer.initialize((progress) => {
222
+ * updateProgressBar(progress.percent)
223
+ * })
224
+ *
225
+ * // Register providers
226
+ * await composer.registerProvider(noirProvider)
227
+ *
228
+ * // Compose proofs with progress
229
+ * const result = await composer.compose({
230
+ * proofs: [proof1, proof2],
231
+ * strategy: ProofAggregationStrategy.PARALLEL,
232
+ * onProgress: (progress) => {
233
+ * console.log(`${progress.stage}: ${progress.percent}%`)
234
+ * },
235
+ * })
236
+ * ```
237
+ */
238
+ /**
239
+ * Internal resolved config type
240
+ */
241
+ interface ResolvedBrowserConfig {
242
+ useWorker: boolean
243
+ verbose: boolean
244
+ maxMemoryBytes: number
245
+ chunkSize: number
246
+ enableProgressReporting: boolean
247
+ workerInitTimeoutMs: number
248
+ forceInitialize: boolean
249
+ mobileMode: boolean
250
+ timeoutMs: number
251
+ maxProofs: number
252
+ maxParallelWorkers: number
253
+ enableParallelGeneration: boolean
254
+ strategy: ProofAggregationStrategy
255
+ }
256
+
257
+ export class BrowserProofComposer implements ProofComposer {
258
+ // ─── Private State ──────────────────────────────────────────────────────
259
+
260
+ private readonly _config: ResolvedBrowserConfig
261
+ private readonly _baseComposer: BaseProofComposer
262
+ private _worker: Worker | null = null
263
+ private _workerUrl: string | null = null
264
+ private _messageChannel: MessageChannel | null = null
265
+ private _pendingRequests: Map<string, {
266
+ resolve: (value: unknown) => void
267
+ reject: (error: Error) => void
268
+ onProgress?: CompositionProgressCallback
269
+ }> = new Map()
270
+ private _requestCounter = 0
271
+ private _isReady = false
272
+ private _initPromise: Promise<void> | null = null
273
+ private _initError: Error | null = null
274
+
275
+ // Device info
276
+ private _deviceInfo: MobileDeviceInfo | null = null
277
+ private _wasmCompat: MobileWASMCompatibility | null = null
278
+ private _maxMemory: number = 512 * 1024 * 1024 // 512MB default
279
+
280
+ // ─── Constructor ────────────────────────────────────────────────────────
281
+
282
+ constructor(config: BrowserProofComposerConfig = {}) {
283
+ // Detect device info
284
+ this._deviceInfo = getMobileDeviceInfo()
285
+ const isMobile = this._deviceInfo.isMobile
286
+
287
+ // Set mobile-appropriate defaults
288
+ const defaultChunkSize = isMobile ? 3 : 5
289
+ const defaultTimeout = isMobile ? 120000 : 60000
290
+
291
+ this._config = {
292
+ useWorker: config.useWorker ?? true,
293
+ verbose: config.verbose ?? false,
294
+ maxMemoryBytes: config.maxMemoryBytes ?? 0, // 0 = auto-detect
295
+ chunkSize: config.chunkSize ?? defaultChunkSize,
296
+ enableProgressReporting: config.enableProgressReporting ?? true,
297
+ workerInitTimeoutMs: config.workerInitTimeoutMs ?? 30000,
298
+ forceInitialize: config.forceInitialize ?? false,
299
+ mobileMode: config.mobileMode ?? isMobile,
300
+ timeoutMs: config.timeoutMs ?? defaultTimeout,
301
+ maxProofs: config.maxProofs ?? DEFAULT_COMPOSITION_CONFIG.maxProofs,
302
+ maxParallelWorkers: config.maxParallelWorkers ?? DEFAULT_COMPOSITION_CONFIG.maxParallelWorkers,
303
+ enableParallelGeneration: config.enableParallelGeneration ?? !isMobile,
304
+ strategy: config.strategy ?? DEFAULT_COMPOSITION_CONFIG.strategy,
305
+ }
306
+
307
+ // Create base composer
308
+ this._baseComposer = new BaseProofComposer({
309
+ timeoutMs: this._config.timeoutMs,
310
+ maxProofs: this._config.maxProofs,
311
+ enableParallelGeneration: !isMobile, // Disable parallel on mobile
312
+ maxParallelWorkers: isMobile ? 2 : this._config.maxParallelWorkers,
313
+ })
314
+
315
+ // Warn if not in browser
316
+ if (!isBrowser()) {
317
+ console.warn(
318
+ '[BrowserProofComposer] Not running in browser environment. ' +
319
+ 'Consider using BaseProofComposer directly for Node.js.'
320
+ )
321
+ }
322
+
323
+ if (this._config.verbose && this._deviceInfo) {
324
+ console.log('[BrowserProofComposer] Device info:', this._deviceInfo)
325
+ }
326
+ }
327
+
328
+ // ─── Static Methods ─────────────────────────────────────────────────────
329
+
330
+ /**
331
+ * Check browser compatibility for proof composition
332
+ */
333
+ static checkCompatibility(): MobileWASMCompatibility {
334
+ return checkMobileWASMCompatibility()
335
+ }
336
+
337
+ /**
338
+ * Check if browser supports all required features
339
+ */
340
+ static checkBrowserSupport(): {
341
+ supported: boolean
342
+ missing: string[]
343
+ } {
344
+ const missing: string[] = []
345
+
346
+ if (!isBrowser()) {
347
+ missing.push('browser environment')
348
+ }
349
+
350
+ if (typeof WebAssembly === 'undefined') {
351
+ missing.push('WebAssembly')
352
+ }
353
+
354
+ if (!supportsWebWorkers()) {
355
+ missing.push('Web Workers')
356
+ }
357
+
358
+ return {
359
+ supported: missing.length === 0,
360
+ missing,
361
+ }
362
+ }
363
+
364
+ /**
365
+ * Get recommended configuration for current device
366
+ */
367
+ static getRecommendedConfig(): Partial<BrowserProofComposerConfig> {
368
+ const deviceInfo = getMobileDeviceInfo()
369
+ const compat = checkMobileWASMCompatibility()
370
+
371
+ const config: Partial<BrowserProofComposerConfig> = {}
372
+
373
+ if (deviceInfo.isMobile) {
374
+ config.mobileMode = true
375
+ config.chunkSize = 3
376
+ config.timeoutMs = 120000
377
+
378
+ // Disable workers on low memory devices
379
+ if (deviceInfo.deviceMemoryGB !== null && deviceInfo.deviceMemoryGB < 2) {
380
+ config.useWorker = false
381
+ }
382
+ }
383
+
384
+ if (!compat.sharedArrayBuffer) {
385
+ // Some operations may be slower without SAB
386
+ config.chunkSize = Math.max(2, (config.chunkSize ?? 5) - 2)
387
+ }
388
+
389
+ return config
390
+ }
391
+
392
+ /**
393
+ * Check if current device is mobile
394
+ */
395
+ static isMobile(): boolean {
396
+ return getMobileDeviceInfo().isMobile
397
+ }
398
+
399
+ // ─── Getters ────────────────────────────────────────────────────────────
400
+
401
+ get config(): ProofCompositionConfig {
402
+ return this._baseComposer.config
403
+ }
404
+
405
+ get isReady(): boolean {
406
+ return this._isReady
407
+ }
408
+
409
+ get deviceInfo(): MobileDeviceInfo | null {
410
+ return this._deviceInfo
411
+ }
412
+
413
+ get wasmCompatibility(): MobileWASMCompatibility | null {
414
+ return this._wasmCompat
415
+ }
416
+
417
+ // ─── Configuration ──────────────────────────────────────────────────────
418
+
419
+ updateConfig(config: Partial<ProofCompositionConfig>): void {
420
+ this._baseComposer.updateConfig(config)
421
+ Object.assign(this._config, config)
422
+ }
423
+
424
+ // ─── Provider Management ────────────────────────────────────────────────
425
+
426
+ async registerProvider(
427
+ provider: ComposableProofProvider,
428
+ options?: RegisterProviderOptions
429
+ ): Promise<ProofProviderRegistration> {
430
+ return this._baseComposer.registerProvider(provider, options)
431
+ }
432
+
433
+ unregisterProvider(providerId: string): boolean {
434
+ return this._baseComposer.unregisterProvider(providerId)
435
+ }
436
+
437
+ getProvider(providerId: string): ComposableProofProvider | undefined {
438
+ return this._baseComposer.getProvider(providerId)
439
+ }
440
+
441
+ getProviderForSystem(system: ProofSystem): ComposableProofProvider | undefined {
442
+ return this._baseComposer.getProviderForSystem(system)
443
+ }
444
+
445
+ getProviders(): ProofProviderRegistration[] {
446
+ return this._baseComposer.getProviders()
447
+ }
448
+
449
+ getAvailableSystems(): ProofSystem[] {
450
+ return this._baseComposer.getAvailableSystems()
451
+ }
452
+
453
+ // ─── Initialization ─────────────────────────────────────────────────────
454
+
455
+ /**
456
+ * Initialize the browser composer
457
+ *
458
+ * @param onProgress - Optional progress callback
459
+ */
460
+ async initialize(onProgress?: CompositionProgressCallback): Promise<void> {
461
+ if (this._isReady) return
462
+
463
+ if (this._initPromise) {
464
+ return this._initPromise
465
+ }
466
+
467
+ if (this._initError) {
468
+ throw this._initError
469
+ }
470
+
471
+ this._initPromise = this._doInitialize(onProgress)
472
+
473
+ try {
474
+ await this._initPromise
475
+ } catch (error) {
476
+ this._initError = error instanceof Error ? error : new Error(String(error))
477
+ this._initPromise = null
478
+ throw error
479
+ }
480
+ }
481
+
482
+ /**
483
+ * Wait for composer to be ready
484
+ */
485
+ async waitUntilReady(timeoutMs?: number): Promise<void> {
486
+ if (this._isReady) return
487
+
488
+ const effectiveTimeout = timeoutMs ?? this._config.workerInitTimeoutMs
489
+
490
+ const initPromise = this._initPromise ?? this.initialize()
491
+
492
+ const timeoutPromise = new Promise<never>((_, reject) => {
493
+ setTimeout(() => {
494
+ reject(new CompositionTimeoutError(effectiveTimeout))
495
+ }, effectiveTimeout)
496
+ })
497
+
498
+ await Promise.race([initPromise, timeoutPromise])
499
+ }
500
+
501
+ private async _doInitialize(onProgress?: CompositionProgressCallback): Promise<void> {
502
+ // Check compatibility
503
+ this._wasmCompat = checkMobileWASMCompatibility()
504
+
505
+ onProgress?.({
506
+ stage: 'initializing',
507
+ percent: 0,
508
+ message: 'Checking browser compatibility...',
509
+ })
510
+
511
+ if (this._config.verbose) {
512
+ console.log('[BrowserProofComposer] WASM compatibility:', this._wasmCompat)
513
+ }
514
+
515
+ // Warn on poor compatibility
516
+ if (this._wasmCompat.score < 50 && !this._config.forceInitialize) {
517
+ throw new ProofCompositionError(
518
+ 'BROWSER_INCOMPATIBLE',
519
+ `Browser has poor WASM compatibility (score: ${this._wasmCompat.score}). ` +
520
+ `Issues: ${this._wasmCompat.issues.join(', ')}. ` +
521
+ `Set forceInitialize: true to override.`
522
+ )
523
+ }
524
+
525
+ onProgress?.({
526
+ stage: 'initializing',
527
+ percent: 20,
528
+ message: 'Detecting memory limits...',
529
+ })
530
+
531
+ // Detect memory limits
532
+ if (this._config.maxMemoryBytes > 0) {
533
+ this._maxMemory = this._config.maxMemoryBytes
534
+ } else {
535
+ const available = await estimateAvailableMemory()
536
+ if (available) {
537
+ // Use 50% of available memory as limit
538
+ this._maxMemory = Math.floor(available * 0.5)
539
+ } else if (this._deviceInfo?.deviceMemoryGB) {
540
+ // Use 25% of device memory (conservative for mobile)
541
+ this._maxMemory = Math.floor(this._deviceInfo.deviceMemoryGB * 1024 * 1024 * 1024 * 0.25)
542
+ }
543
+ }
544
+
545
+ if (this._config.verbose) {
546
+ console.log('[BrowserProofComposer] Max memory:', this._maxMemory, 'bytes')
547
+ }
548
+
549
+ onProgress?.({
550
+ stage: 'initializing',
551
+ percent: 40,
552
+ message: 'Initializing base composer...',
553
+ })
554
+
555
+ // Initialize base composer
556
+ await this._baseComposer.initialize()
557
+
558
+ // Initialize worker if enabled and supported
559
+ if (this._config.useWorker && supportsWebWorkers()) {
560
+ onProgress?.({
561
+ stage: 'initializing',
562
+ percent: 60,
563
+ message: 'Setting up Web Worker...',
564
+ })
565
+
566
+ await this._initializeWorker()
567
+ }
568
+
569
+ // Set up message channel for progress
570
+ if (this._config.enableProgressReporting) {
571
+ onProgress?.({
572
+ stage: 'initializing',
573
+ percent: 80,
574
+ message: 'Setting up progress channel...',
575
+ })
576
+
577
+ this._messageChannel = new MessageChannel()
578
+ }
579
+
580
+ this._isReady = true
581
+
582
+ onProgress?.({
583
+ stage: 'complete',
584
+ percent: 100,
585
+ message: 'Ready for proof composition',
586
+ })
587
+
588
+ if (this._config.verbose) {
589
+ console.log('[BrowserProofComposer] Initialization complete')
590
+ }
591
+ }
592
+
593
+ private async _initializeWorker(): Promise<void> {
594
+ if (!supportsWebWorkers()) {
595
+ if (this._config.verbose) {
596
+ console.log('[BrowserProofComposer] Web Workers not supported, using main thread')
597
+ }
598
+ return
599
+ }
600
+
601
+ try {
602
+ const workerCode = this._getWorkerCode()
603
+ this._workerUrl = createWorkerBlobUrl(workerCode)
604
+ this._worker = new Worker(this._workerUrl, { type: 'module' })
605
+
606
+ // Set up message handler
607
+ this._worker.onmessage = (event: MessageEvent<WorkerResponse>) => {
608
+ this._handleWorkerMessage(event.data)
609
+ }
610
+
611
+ this._worker.onerror = (error) => {
612
+ console.error('[BrowserProofComposer] Worker error:', error)
613
+ this._cleanupWorker()
614
+ }
615
+
616
+ if (this._config.verbose) {
617
+ console.log('[BrowserProofComposer] Web Worker initialized')
618
+ }
619
+ } catch (error) {
620
+ if (this._config.verbose) {
621
+ console.warn('[BrowserProofComposer] Failed to initialize worker:', error)
622
+ }
623
+ this._cleanupWorker()
624
+ }
625
+ }
626
+
627
+ private _getWorkerCode(): string {
628
+ return `
629
+ // Browser Proof Composition Worker
630
+ let isReady = false;
631
+
632
+ function sendProgress(id, progress) {
633
+ self.postMessage({
634
+ id,
635
+ type: 'progress',
636
+ progress
637
+ });
638
+ }
639
+
640
+ function sendSuccess(id, result) {
641
+ self.postMessage({
642
+ id,
643
+ type: 'success',
644
+ result
645
+ });
646
+ }
647
+
648
+ function sendError(id, error) {
649
+ self.postMessage({
650
+ id,
651
+ type: 'error',
652
+ error: error.message || String(error)
653
+ });
654
+ }
655
+
656
+ async function processComposition(id, payload) {
657
+ const { proofs, strategy } = payload;
658
+
659
+ try {
660
+ sendProgress(id, {
661
+ stage: 'validating',
662
+ percent: 10,
663
+ message: 'Validating proofs...',
664
+ totalProofs: proofs.length
665
+ });
666
+
667
+ // Validate proofs
668
+ for (let i = 0; i < proofs.length; i++) {
669
+ if (!proofs[i] || !proofs[i].proof) {
670
+ throw new Error('Invalid proof at index ' + i);
671
+ }
672
+
673
+ sendProgress(id, {
674
+ stage: 'processing',
675
+ percent: 10 + Math.floor((i / proofs.length) * 70),
676
+ message: 'Processing proof ' + (i + 1) + '/' + proofs.length,
677
+ currentProof: i + 1,
678
+ totalProofs: proofs.length
679
+ });
680
+
681
+ // Simulate processing time
682
+ await new Promise(r => setTimeout(r, 10));
683
+ }
684
+
685
+ sendProgress(id, {
686
+ stage: 'aggregating',
687
+ percent: 80,
688
+ message: 'Aggregating proofs...'
689
+ });
690
+
691
+ // Aggregation (worker returns signal to continue on main thread)
692
+ sendProgress(id, {
693
+ stage: 'complete',
694
+ percent: 100,
695
+ message: 'Worker processing complete'
696
+ });
697
+
698
+ sendSuccess(id, { processed: true, proofCount: proofs.length });
699
+ } catch (error) {
700
+ sendError(id, error);
701
+ }
702
+ }
703
+
704
+ self.onmessage = async function(event) {
705
+ const { id, type, payload } = event.data;
706
+
707
+ switch (type) {
708
+ case 'init':
709
+ isReady = true;
710
+ sendSuccess(id, { initialized: true });
711
+ break;
712
+
713
+ case 'compose':
714
+ if (!isReady) {
715
+ sendError(id, new Error('Worker not initialized'));
716
+ return;
717
+ }
718
+ await processComposition(id, payload);
719
+ break;
720
+
721
+ case 'dispose':
722
+ isReady = false;
723
+ sendSuccess(id, { disposed: true });
724
+ break;
725
+
726
+ default:
727
+ sendError(id, new Error('Unknown message type: ' + type));
728
+ }
729
+ };
730
+ `
731
+ }
732
+
733
+ private _handleWorkerMessage(response: WorkerResponse): void {
734
+ const pending = this._pendingRequests.get(response.id)
735
+ if (!pending) {
736
+ if (this._config.verbose) {
737
+ console.warn('[BrowserProofComposer] Unknown request ID:', response.id)
738
+ }
739
+ return
740
+ }
741
+
742
+ switch (response.type) {
743
+ case 'success':
744
+ this._pendingRequests.delete(response.id)
745
+ pending.resolve(response.result)
746
+ break
747
+
748
+ case 'error':
749
+ this._pendingRequests.delete(response.id)
750
+ pending.reject(new Error(response.error))
751
+ break
752
+
753
+ case 'progress':
754
+ if (response.progress) {
755
+ pending.onProgress?.(response.progress)
756
+ }
757
+ break
758
+ }
759
+ }
760
+
761
+ private _sendToWorker<T>(
762
+ type: WorkerMessageType,
763
+ payload?: unknown,
764
+ onProgress?: CompositionProgressCallback
765
+ ): Promise<T> {
766
+ return new Promise((resolve, reject) => {
767
+ if (!this._worker) {
768
+ reject(new Error('Worker not available'))
769
+ return
770
+ }
771
+
772
+ const id = `req_${++this._requestCounter}_${Date.now()}`
773
+ this._pendingRequests.set(id, {
774
+ resolve: resolve as (value: unknown) => void,
775
+ reject,
776
+ onProgress,
777
+ })
778
+
779
+ const request: WorkerRequest = { id, type, payload }
780
+ this._worker.postMessage(request)
781
+ })
782
+ }
783
+
784
+ private _cleanupWorker(): void {
785
+ if (this._worker) {
786
+ this._worker.terminate()
787
+ this._worker = null
788
+ }
789
+
790
+ if (this._workerUrl) {
791
+ revokeWorkerBlobUrl(this._workerUrl)
792
+ this._workerUrl = null
793
+ }
794
+
795
+ // Reject all pending requests
796
+ for (const [id, { reject }] of this._pendingRequests) {
797
+ reject(new Error('Worker terminated'))
798
+ this._pendingRequests.delete(id)
799
+ }
800
+ }
801
+
802
+ // ─── Proof Generation ───────────────────────────────────────────────────
803
+
804
+ async generateProof(request: ProofGenerationRequest): Promise<ProofGenerationResult> {
805
+ this._ensureReady()
806
+ return this._baseComposer.generateProof(request)
807
+ }
808
+
809
+ async generateProofs(requests: ProofGenerationRequest[]): Promise<ProofGenerationResult[]> {
810
+ this._ensureReady()
811
+ return this._baseComposer.generateProofs(requests)
812
+ }
813
+
814
+ // ─── Composition ────────────────────────────────────────────────────────
815
+
816
+ /**
817
+ * Compose proofs (implements ProofComposer interface)
818
+ */
819
+ async compose(options: ComposeProofsOptions): Promise<CompositionResult> {
820
+ this._ensureReady()
821
+ return this._baseComposer.compose(options)
822
+ }
823
+
824
+ /**
825
+ * Compose proofs with browser optimizations and progress reporting
826
+ *
827
+ * Use this method when you need progress updates in the browser UI.
828
+ */
829
+ async composeWithProgress(options: BrowserComposeOptions): Promise<CompositionResult> {
830
+ this._ensureReady()
831
+
832
+ const { proofs, strategy, onProgress } = options
833
+
834
+ // Report initial progress
835
+ onProgress?.({
836
+ stage: 'initializing',
837
+ percent: 0,
838
+ message: 'Starting composition...',
839
+ totalProofs: proofs.length,
840
+ })
841
+
842
+ // Check memory constraints
843
+ const estimatedMemory = this._estimateMemoryUsage(proofs)
844
+ if (estimatedMemory > this._maxMemory) {
845
+ if (this._config.verbose) {
846
+ console.log(
847
+ '[BrowserProofComposer] Proof set too large, using chunked processing:',
848
+ estimatedMemory,
849
+ '>',
850
+ this._maxMemory
851
+ )
852
+ }
853
+
854
+ return this._composeChunked(proofs, strategy, onProgress)
855
+ }
856
+
857
+ // Try worker if available
858
+ if (this._worker) {
859
+ try {
860
+ // Let worker do validation and preprocessing
861
+ await this._sendToWorker<{ processed: boolean }>(
862
+ 'compose',
863
+ { proofs, strategy },
864
+ onProgress
865
+ )
866
+ } catch (error) {
867
+ if (this._config.verbose) {
868
+ console.warn('[BrowserProofComposer] Worker composition failed, falling back:', error)
869
+ }
870
+ }
871
+ }
872
+
873
+ // Perform actual composition on main thread (base composer)
874
+ onProgress?.({
875
+ stage: 'aggregating',
876
+ percent: 80,
877
+ message: 'Finalizing composition...',
878
+ })
879
+
880
+ const result = await this._baseComposer.compose({
881
+ proofs,
882
+ strategy,
883
+ config: options.config,
884
+ abortSignal: options.abortSignal,
885
+ onProgress: (event) => {
886
+ // Convert composition event to progress
887
+ if (event.type === 'composition:progress') {
888
+ onProgress?.({
889
+ stage: 'processing',
890
+ percent: 50,
891
+ message: 'Processing...',
892
+ })
893
+ }
894
+ },
895
+ })
896
+
897
+ onProgress?.({
898
+ stage: 'complete',
899
+ percent: 100,
900
+ message: 'Composition complete',
901
+ })
902
+
903
+ return result
904
+ }
905
+
906
+ /**
907
+ * Compose proofs in chunks for memory management
908
+ */
909
+ private async _composeChunked(
910
+ proofs: SingleProof[],
911
+ strategy: ProofAggregationStrategy = Strategy.SEQUENTIAL,
912
+ onProgress?: CompositionProgressCallback
913
+ ): Promise<CompositionResult> {
914
+ const chunkSize = this._config.chunkSize
915
+ const totalChunks = Math.ceil(proofs.length / chunkSize)
916
+ const chunkResults: ComposedProof[] = []
917
+
918
+ for (let i = 0; i < totalChunks; i++) {
919
+ const start = i * chunkSize
920
+ const end = Math.min(start + chunkSize, proofs.length)
921
+ const chunk = proofs.slice(start, end)
922
+
923
+ onProgress?.({
924
+ stage: 'processing',
925
+ percent: Math.floor((i / totalChunks) * 80),
926
+ message: `Processing chunk ${i + 1}/${totalChunks}`,
927
+ currentChunk: i + 1,
928
+ totalChunks,
929
+ currentProof: start + 1,
930
+ totalProofs: proofs.length,
931
+ })
932
+
933
+ const chunkResult = await this._baseComposer.compose({
934
+ proofs: chunk,
935
+ strategy,
936
+ })
937
+
938
+ if (!chunkResult.success || !chunkResult.composedProof) {
939
+ return chunkResult
940
+ }
941
+
942
+ chunkResults.push(chunkResult.composedProof)
943
+
944
+ // Yield to browser
945
+ await new Promise((resolve) => setTimeout(resolve, 0))
946
+ }
947
+
948
+ // Merge chunk results
949
+ onProgress?.({
950
+ stage: 'aggregating',
951
+ percent: 90,
952
+ message: 'Merging chunks...',
953
+ })
954
+
955
+ // Create final composed proof from chunks
956
+ const finalProof: ComposedProof = {
957
+ id: `composed-${Date.now()}-${Math.random().toString(36).slice(2)}`,
958
+ proofs,
959
+ strategy,
960
+ status: ComposedProofStatus.VERIFIED,
961
+ combinedPublicInputs: proofs.flatMap((p) => p.publicInputs),
962
+ compositionMetadata: {
963
+ proofCount: proofs.length,
964
+ systems: [...new Set(proofs.map((p) => p.metadata.system))],
965
+ compositionTimeMs: 0, // Set by caller
966
+ success: true,
967
+ inputHash: `0x${proofs.length.toString(16).padStart(16, '0')}` as `0x${string}`,
968
+ },
969
+ verificationHints: {
970
+ verificationOrder: proofs.map((p) => p.id),
971
+ parallelGroups: [proofs.map((p) => p.id)],
972
+ estimatedTimeMs: proofs.length * 100,
973
+ estimatedCost: BigInt(proofs.length * 100000),
974
+ supportsBatchVerification: strategy === Strategy.BATCH,
975
+ },
976
+ }
977
+
978
+ onProgress?.({
979
+ stage: 'complete',
980
+ percent: 100,
981
+ message: 'Composition complete',
982
+ })
983
+
984
+ return {
985
+ success: true,
986
+ composedProof: finalProof,
987
+ metrics: {
988
+ totalTimeMs: 0,
989
+ generationTimeMs: 0,
990
+ verificationTimeMs: 0,
991
+ aggregationTimeMs: 0,
992
+ peakMemoryBytes: this._maxMemory,
993
+ proofsProcessed: proofs.length,
994
+ },
995
+ }
996
+ }
997
+
998
+ private _estimateMemoryUsage(proofs: SingleProof[]): number {
999
+ // Rough estimate: each proof ~10KB + overhead
1000
+ const baseOverhead = 50 * 1024 // 50KB base
1001
+ const perProofEstimate = 10 * 1024 // 10KB per proof
1002
+
1003
+ return baseOverhead + proofs.length * perProofEstimate
1004
+ }
1005
+
1006
+ async aggregate(options: AggregateProofsOptions): Promise<AggregationResult> {
1007
+ this._ensureReady()
1008
+ return this._baseComposer.aggregate(options)
1009
+ }
1010
+
1011
+ // ─── Verification ───────────────────────────────────────────────────────
1012
+
1013
+ async verify(options: VerifyComposedProofOptions): Promise<VerificationResult> {
1014
+ this._ensureReady()
1015
+ return this._baseComposer.verify(options)
1016
+ }
1017
+
1018
+ async verifySingle(proof: SingleProof): Promise<boolean> {
1019
+ this._ensureReady()
1020
+ return this._baseComposer.verifySingle(proof)
1021
+ }
1022
+
1023
+ // ─── Format Conversion ──────────────────────────────────────────────────
1024
+
1025
+ async convert(options: ConvertProofOptions): Promise<ConversionResult> {
1026
+ this._ensureReady()
1027
+ return this._baseComposer.convert(options)
1028
+ }
1029
+
1030
+ getCompatibilityMatrix(): CompatibilityMatrix {
1031
+ return this._baseComposer.getCompatibilityMatrix()
1032
+ }
1033
+
1034
+ areSystemsCompatible(source: ProofSystem, target: ProofSystem): boolean {
1035
+ return this._baseComposer.areSystemsCompatible(source, target)
1036
+ }
1037
+
1038
+ // ─── Caching ────────────────────────────────────────────────────────────
1039
+
1040
+ getCacheStats(): CacheStats {
1041
+ return this._baseComposer.getCacheStats()
1042
+ }
1043
+
1044
+ clearCache(olderThan?: number): void {
1045
+ this._baseComposer.clearCache(olderThan)
1046
+ }
1047
+
1048
+ // ─── Worker Pool ────────────────────────────────────────────────────────
1049
+
1050
+ getWorkerPoolStatus(): WorkerPoolStatus {
1051
+ const baseStatus = this._baseComposer.getWorkerPoolStatus()
1052
+
1053
+ return {
1054
+ ...baseStatus,
1055
+ // Add browser worker info
1056
+ activeWorkers: this._worker ? 1 : 0,
1057
+ }
1058
+ }
1059
+
1060
+ async scaleWorkerPool(targetWorkers: number): Promise<void> {
1061
+ return this._baseComposer.scaleWorkerPool(targetWorkers)
1062
+ }
1063
+
1064
+ // ─── Fallback Configuration ─────────────────────────────────────────────
1065
+
1066
+ setFallbackConfig(config: FallbackConfig): void {
1067
+ this._baseComposer.setFallbackConfig(config)
1068
+ }
1069
+
1070
+ getFallbackConfig(): FallbackConfig | undefined {
1071
+ return this._baseComposer.getFallbackConfig()
1072
+ }
1073
+
1074
+ // ─── Events ─────────────────────────────────────────────────────────────
1075
+
1076
+ addEventListener(listener: CompositionEventListener): () => void {
1077
+ return this._baseComposer.addEventListener(listener)
1078
+ }
1079
+
1080
+ removeEventListener(listener: CompositionEventListener): void {
1081
+ this._baseComposer.removeEventListener(listener)
1082
+ }
1083
+
1084
+ // ─── Telemetry ──────────────────────────────────────────────────────────
1085
+
1086
+ setTelemetryCollector(collector: TelemetryCollector): void {
1087
+ this._baseComposer.setTelemetryCollector(collector)
1088
+ }
1089
+
1090
+ // ─── Lifecycle ──────────────────────────────────────────────────────────
1091
+
1092
+ async dispose(): Promise<void> {
1093
+ // Cleanup worker
1094
+ this._cleanupWorker()
1095
+
1096
+ // Cleanup message channel
1097
+ if (this._messageChannel) {
1098
+ this._messageChannel.port1.close()
1099
+ this._messageChannel.port2.close()
1100
+ this._messageChannel = null
1101
+ }
1102
+
1103
+ // Dispose base composer
1104
+ await this._baseComposer.dispose()
1105
+
1106
+ this._isReady = false
1107
+ }
1108
+
1109
+ // ─── Private Utilities ──────────────────────────────────────────────────
1110
+
1111
+ private _ensureReady(): void {
1112
+ if (!this._isReady) {
1113
+ throw new ProofCompositionError(
1114
+ 'NOT_INITIALIZED',
1115
+ 'BrowserProofComposer not initialized. Call initialize() first.'
1116
+ )
1117
+ }
1118
+ }
1119
+ }
1120
+
1121
+ // ─── Factory Function ───────────────────────────────────────────────────────
1122
+
1123
+ /**
1124
+ * Create a browser-compatible proof composer
1125
+ *
1126
+ * @example
1127
+ * ```typescript
1128
+ * const composer = createBrowserComposer({ verbose: true })
1129
+ * await composer.initialize()
1130
+ * ```
1131
+ */
1132
+ export function createBrowserComposer(
1133
+ config?: BrowserProofComposerConfig
1134
+ ): BrowserProofComposer {
1135
+ return new BrowserProofComposer(config)
1136
+ }
1137
+
1138
+ /**
1139
+ * Create a composer with automatic environment detection
1140
+ *
1141
+ * Returns BrowserProofComposer in browser, BaseProofComposer in Node.js
1142
+ */
1143
+ export function createAutoComposer(
1144
+ config?: BrowserProofComposerConfig
1145
+ ): ProofComposer {
1146
+ if (isBrowser()) {
1147
+ return new BrowserProofComposer(config)
1148
+ }
1149
+ return new BaseProofComposer(config)
1150
+ }