@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,1029 @@
1
+ /**
2
+ * Proof Aggregator
3
+ *
4
+ * Implements core proof aggregation logic for combining multiple proofs
5
+ * from different ZK systems into composed proofs.
6
+ *
7
+ * Key features:
8
+ * - Sequential aggregation (prove A, then B with A as input)
9
+ * - Parallel aggregation (prove A and B independently, combine)
10
+ * - Recursive aggregation (proof-of-proofs)
11
+ * - Cross-system proof linking
12
+ * - Failure recovery and retry logic
13
+ * - Progress tracking
14
+ *
15
+ * @packageDocumentation
16
+ */
17
+
18
+ import { randomBytes, bytesToHex } from '@noble/hashes/utils'
19
+
20
+ import type {
21
+ ProofSystem,
22
+ ProofAggregationStrategy,
23
+ SingleProof,
24
+ ComposedProof,
25
+ CompositionEvent,
26
+ CompositionEventListener,
27
+ VerificationHints,
28
+ HexString,
29
+ } from '@sip-protocol/types'
30
+
31
+ import {
32
+ ProofAggregationStrategy as Strategy,
33
+ ComposedProofStatus,
34
+ } from '@sip-protocol/types'
35
+
36
+ import type { ComposableProofProvider } from './composer/interface'
37
+
38
+ import type {
39
+ AggregationResult,
40
+ } from './composer/types'
41
+
42
+ // ─── Types ───────────────────────────────────────────────────────────────────
43
+
44
+ /**
45
+ * Configuration for the aggregator
46
+ */
47
+ export interface AggregatorConfig {
48
+ /** Maximum number of proofs to aggregate */
49
+ maxProofs: number
50
+ /** Maximum recursion depth for recursive aggregation */
51
+ maxRecursionDepth: number
52
+ /** Timeout for aggregation operations (ms) */
53
+ timeoutMs: number
54
+ /** Enable parallel processing */
55
+ enableParallel: boolean
56
+ /** Maximum parallel operations */
57
+ maxParallelOps: number
58
+ /** Retry configuration */
59
+ retry: {
60
+ enabled: boolean
61
+ maxAttempts: number
62
+ delayMs: number
63
+ exponentialBackoff: boolean
64
+ }
65
+ /** Enable verbose logging */
66
+ verbose: boolean
67
+ }
68
+
69
+ /**
70
+ * Progress event for aggregation
71
+ */
72
+ export interface AggregationProgressEvent {
73
+ /** Current step */
74
+ step: number
75
+ /** Total steps */
76
+ totalSteps: number
77
+ /** Operation description */
78
+ operation: string
79
+ /** Proof being processed (if applicable) */
80
+ proofId?: string
81
+ /** Time elapsed so far */
82
+ elapsedMs: number
83
+ }
84
+
85
+ /**
86
+ * Callback for aggregation progress
87
+ */
88
+ export type AggregationProgressCallback = (event: AggregationProgressEvent) => void
89
+
90
+ /**
91
+ * Options for sequential aggregation
92
+ */
93
+ export interface SequentialAggregationOptions {
94
+ /** Proofs to aggregate in order */
95
+ proofs: SingleProof[]
96
+ /** Provider lookup function */
97
+ getProvider: (system: ProofSystem) => ComposableProofProvider | undefined
98
+ /** Progress callback */
99
+ onProgress?: AggregationProgressCallback
100
+ /** Abort signal */
101
+ abortSignal?: AbortSignal
102
+ /** Whether to verify before aggregating */
103
+ verifyBefore: boolean
104
+ /** Custom linking function for sequential proofs */
105
+ linkProofs?: (previous: SingleProof, current: SingleProof) => HexString | undefined
106
+ }
107
+
108
+ /**
109
+ * Options for parallel aggregation
110
+ */
111
+ export interface ParallelAggregationOptions {
112
+ /** Proofs to aggregate */
113
+ proofs: SingleProof[]
114
+ /** Provider lookup function */
115
+ getProvider: (system: ProofSystem) => ComposableProofProvider | undefined
116
+ /** Progress callback */
117
+ onProgress?: AggregationProgressCallback
118
+ /** Abort signal */
119
+ abortSignal?: AbortSignal
120
+ /** Maximum concurrent operations */
121
+ maxConcurrent: number
122
+ /** Whether to verify before aggregating */
123
+ verifyBefore: boolean
124
+ }
125
+
126
+ /**
127
+ * Options for recursive aggregation
128
+ */
129
+ export interface RecursiveAggregationOptions {
130
+ /** Proofs to aggregate */
131
+ proofs: SingleProof[]
132
+ /** Provider lookup function */
133
+ getProvider: (system: ProofSystem) => ComposableProofProvider | undefined
134
+ /** Target system for recursion */
135
+ targetSystem: ProofSystem
136
+ /** Maximum recursion depth */
137
+ maxDepth: number
138
+ /** Progress callback */
139
+ onProgress?: AggregationProgressCallback
140
+ /** Abort signal */
141
+ abortSignal?: AbortSignal
142
+ }
143
+
144
+ /**
145
+ * Result of a single aggregation step
146
+ */
147
+ export interface AggregationStepResult {
148
+ /** Whether the step succeeded */
149
+ success: boolean
150
+ /** Resulting proof (if successful) */
151
+ proof?: SingleProof
152
+ /** Error message (if failed) */
153
+ error?: string
154
+ /** Time taken for this step */
155
+ timeMs: number
156
+ /** Depth in recursive aggregation */
157
+ depth: number
158
+ }
159
+
160
+ /**
161
+ * Detailed aggregation result with step information
162
+ */
163
+ export interface DetailedAggregationResult extends AggregationResult {
164
+ /** Results from each aggregation step */
165
+ stepResults: AggregationStepResult[]
166
+ /** Final composed proof */
167
+ composedProof?: ComposedProof
168
+ /** Retry information */
169
+ retries: {
170
+ attempted: number
171
+ succeeded: number
172
+ failed: number
173
+ }
174
+ }
175
+
176
+ // ─── Default Configuration ───────────────────────────────────────────────────
177
+
178
+ const DEFAULT_AGGREGATOR_CONFIG: AggregatorConfig = {
179
+ maxProofs: 100,
180
+ maxRecursionDepth: 10,
181
+ timeoutMs: 300000, // 5 minutes
182
+ enableParallel: true,
183
+ maxParallelOps: 4,
184
+ retry: {
185
+ enabled: true,
186
+ maxAttempts: 3,
187
+ delayMs: 1000,
188
+ exponentialBackoff: true,
189
+ },
190
+ verbose: false,
191
+ }
192
+
193
+ // ─── Helper Functions ────────────────────────────────────────────────────────
194
+
195
+ /**
196
+ * Generate a unique ID
197
+ */
198
+ function generateId(prefix: string): string {
199
+ const bytes = randomBytes(8)
200
+ return `${prefix}-${bytesToHex(bytes)}`
201
+ }
202
+
203
+ /**
204
+ * Compute hash of proof data
205
+ */
206
+ function computeProofHash(proofs: SingleProof[]): HexString {
207
+ const data = proofs.map(p => p.proof).join('')
208
+ let hash = 0
209
+ for (let i = 0; i < data.length; i++) {
210
+ const char = data.charCodeAt(i)
211
+ hash = ((hash << 5) - hash) + char
212
+ hash = hash & hash
213
+ }
214
+ return `0x${Math.abs(hash).toString(16).padStart(16, '0')}` as HexString
215
+ }
216
+
217
+ /**
218
+ * Delay helper
219
+ */
220
+ function delay(ms: number): Promise<void> {
221
+ return new Promise(resolve => setTimeout(resolve, ms))
222
+ }
223
+
224
+ /**
225
+ * Create a timeout promise
226
+ */
227
+ function createTimeout(ms: number): { promise: Promise<never>; cancel: () => void } {
228
+ let timeoutId: ReturnType<typeof setTimeout>
229
+ const promise = new Promise<never>((_, reject) => {
230
+ timeoutId = setTimeout(() => reject(new Error(`Timeout after ${ms}ms`)), ms)
231
+ })
232
+ return {
233
+ promise,
234
+ cancel: () => clearTimeout(timeoutId),
235
+ }
236
+ }
237
+
238
+ // ─── Proof Aggregator ────────────────────────────────────────────────────────
239
+
240
+ /**
241
+ * Proof Aggregator
242
+ *
243
+ * Implements aggregation logic for combining multiple ZK proofs.
244
+ *
245
+ * @example
246
+ * ```typescript
247
+ * const aggregator = new ProofAggregator()
248
+ *
249
+ * // Sequential aggregation
250
+ * const result = await aggregator.aggregateSequential({
251
+ * proofs: [proof1, proof2, proof3],
252
+ * getProvider: (system) => composer.getProviderForSystem(system),
253
+ * verifyBefore: true,
254
+ * })
255
+ *
256
+ * // Parallel aggregation
257
+ * const parallelResult = await aggregator.aggregateParallel({
258
+ * proofs: [proofA, proofB, proofC],
259
+ * getProvider: (system) => composer.getProviderForSystem(system),
260
+ * maxConcurrent: 3,
261
+ * verifyBefore: true,
262
+ * })
263
+ *
264
+ * // Recursive aggregation
265
+ * const recursiveResult = await aggregator.aggregateRecursive({
266
+ * proofs: proofs,
267
+ * getProvider: (system) => composer.getProviderForSystem(system),
268
+ * targetSystem: 'kimchi',
269
+ * maxDepth: 5,
270
+ * })
271
+ * ```
272
+ */
273
+ export class ProofAggregator {
274
+ private _config: AggregatorConfig
275
+ private _eventListeners: Set<CompositionEventListener> = new Set()
276
+
277
+ constructor(config?: Partial<AggregatorConfig>) {
278
+ this._config = { ...DEFAULT_AGGREGATOR_CONFIG, ...config }
279
+ }
280
+
281
+ // ─── Configuration ─────────────────────────────────────────────────────────
282
+
283
+ get config(): AggregatorConfig {
284
+ return { ...this._config }
285
+ }
286
+
287
+ updateConfig(config: Partial<AggregatorConfig>): void {
288
+ this._config = { ...this._config, ...config }
289
+ }
290
+
291
+ // ─── Sequential Aggregation ────────────────────────────────────────────────
292
+
293
+ /**
294
+ * Aggregate proofs sequentially.
295
+ *
296
+ * Each proof is processed in order, with optional linking
297
+ * between consecutive proofs.
298
+ */
299
+ async aggregateSequential(options: SequentialAggregationOptions): Promise<DetailedAggregationResult> {
300
+ const startTime = Date.now()
301
+ const compositionId = generateId('seq-agg')
302
+ const { proofs, getProvider, onProgress, abortSignal, verifyBefore, linkProofs } = options
303
+ const stepResults: AggregationStepResult[] = []
304
+ const totalSteps = proofs.length
305
+ const retryStats = { attempted: 0, succeeded: 0, failed: 0 }
306
+
307
+ // Emit start event
308
+ this.emitEvent({
309
+ type: 'composition:started',
310
+ timestamp: Date.now(),
311
+ compositionId,
312
+ })
313
+
314
+ if (this._config.verbose) {
315
+ console.log(`[Aggregator] Sequential aggregation of ${proofs.length} proofs`)
316
+ }
317
+
318
+ // Validate inputs
319
+ if (proofs.length === 0) {
320
+ return this.createFailedResult('No proofs to aggregate', startTime, stepResults, retryStats)
321
+ }
322
+
323
+ if (proofs.length > this._config.maxProofs) {
324
+ return this.createFailedResult(
325
+ `Too many proofs: ${proofs.length} > ${this._config.maxProofs}`,
326
+ startTime,
327
+ stepResults,
328
+ retryStats,
329
+ )
330
+ }
331
+
332
+ const verifiedProofs: SingleProof[] = []
333
+
334
+ for (let i = 0; i < proofs.length; i++) {
335
+ // Check for abort
336
+ if (abortSignal?.aborted) {
337
+ return this.createFailedResult('Aggregation aborted', startTime, stepResults, retryStats)
338
+ }
339
+
340
+ const proof = proofs[i]
341
+ const stepStartTime = Date.now()
342
+
343
+ // Report progress
344
+ onProgress?.({
345
+ step: i + 1,
346
+ totalSteps,
347
+ operation: `Processing proof ${i + 1}/${totalSteps}`,
348
+ proofId: proof.id,
349
+ elapsedMs: Date.now() - startTime,
350
+ })
351
+
352
+ // Verify if requested
353
+ if (verifyBefore) {
354
+ const provider = getProvider(proof.metadata.system)
355
+ if (!provider) {
356
+ stepResults.push({
357
+ success: false,
358
+ error: `No provider for system: ${proof.metadata.system}`,
359
+ timeMs: Date.now() - stepStartTime,
360
+ depth: 0,
361
+ })
362
+ continue
363
+ }
364
+
365
+ // Retry logic for verification
366
+ let verified = false
367
+ let lastError: string | undefined
368
+
369
+ for (let attempt = 0; attempt < (this._config.retry.enabled ? this._config.retry.maxAttempts : 1); attempt++) {
370
+ if (attempt > 0) {
371
+ retryStats.attempted++
372
+ const delayTime = this._config.retry.exponentialBackoff
373
+ ? this._config.retry.delayMs * Math.pow(2, attempt - 1)
374
+ : this._config.retry.delayMs
375
+ await delay(delayTime)
376
+ }
377
+
378
+ try {
379
+ verified = await provider.verifyProof(proof)
380
+ if (verified) {
381
+ if (attempt > 0) retryStats.succeeded++
382
+ break
383
+ }
384
+ lastError = 'Proof verification failed'
385
+ } catch (error) {
386
+ lastError = error instanceof Error ? error.message : 'Unknown error'
387
+ }
388
+ }
389
+
390
+ if (!verified) {
391
+ if (retryStats.attempted > 0) retryStats.failed++
392
+ stepResults.push({
393
+ success: false,
394
+ error: lastError || 'Verification failed',
395
+ timeMs: Date.now() - stepStartTime,
396
+ depth: 0,
397
+ })
398
+ return this.createFailedResult(
399
+ `Proof ${proof.id} failed verification: ${lastError}`,
400
+ startTime,
401
+ stepResults,
402
+ retryStats,
403
+ )
404
+ }
405
+ }
406
+
407
+ // Link with previous proof if function provided
408
+ if (linkProofs && i > 0) {
409
+ const linkHash = linkProofs(verifiedProofs[i - 1], proof)
410
+ if (linkHash) {
411
+ // Store link in proof for later verification
412
+ (proof as SingleProof & { linkHash?: HexString }).linkHash = linkHash
413
+ }
414
+ }
415
+
416
+ verifiedProofs.push(proof)
417
+ stepResults.push({
418
+ success: true,
419
+ proof,
420
+ timeMs: Date.now() - stepStartTime,
421
+ depth: 0,
422
+ })
423
+ }
424
+
425
+ // Create composed proof
426
+ const composedProof = this.createComposedProof(
427
+ verifiedProofs,
428
+ Strategy.SEQUENTIAL,
429
+ startTime,
430
+ )
431
+
432
+ // Emit completed event
433
+ this.emitEvent({
434
+ type: 'composition:completed',
435
+ timestamp: Date.now(),
436
+ compositionId,
437
+ })
438
+
439
+ return {
440
+ success: true,
441
+ aggregatedProof: computeProofHash(verifiedProofs),
442
+ metrics: {
443
+ inputProofCount: proofs.length,
444
+ outputProofSize: composedProof.proofs.length,
445
+ timeMs: Date.now() - startTime,
446
+ recursionDepth: 0,
447
+ },
448
+ stepResults,
449
+ composedProof,
450
+ retries: retryStats,
451
+ }
452
+ }
453
+
454
+ // ─── Parallel Aggregation ──────────────────────────────────────────────────
455
+
456
+ /**
457
+ * Aggregate proofs in parallel.
458
+ *
459
+ * All proofs are processed concurrently, limited by maxConcurrent.
460
+ */
461
+ async aggregateParallel(options: ParallelAggregationOptions): Promise<DetailedAggregationResult> {
462
+ const startTime = Date.now()
463
+ const { proofs, getProvider, onProgress, abortSignal, maxConcurrent, verifyBefore } = options
464
+ const stepResults: AggregationStepResult[] = new Array(proofs.length)
465
+ const retryStats = { attempted: 0, succeeded: 0, failed: 0 }
466
+ let completedCount = 0
467
+
468
+ if (this._config.verbose) {
469
+ console.log(`[Aggregator] Parallel aggregation of ${proofs.length} proofs (max concurrent: ${maxConcurrent})`)
470
+ }
471
+
472
+ // Validate inputs
473
+ if (proofs.length === 0) {
474
+ return this.createFailedResult('No proofs to aggregate', startTime, [], retryStats)
475
+ }
476
+
477
+ if (proofs.length > this._config.maxProofs) {
478
+ return this.createFailedResult(
479
+ `Too many proofs: ${proofs.length} > ${this._config.maxProofs}`,
480
+ startTime,
481
+ [],
482
+ retryStats,
483
+ )
484
+ }
485
+
486
+ // Create work queue
487
+ const queue = proofs.map((proof, index) => ({ proof, index }))
488
+ const verifiedProofs: SingleProof[] = new Array(proofs.length)
489
+ const errors: string[] = []
490
+
491
+ // Worker function
492
+ const worker = async () => {
493
+ while (queue.length > 0) {
494
+ if (abortSignal?.aborted) return
495
+
496
+ const item = queue.shift()
497
+ if (!item) break
498
+
499
+ const { proof, index } = item
500
+ const stepStartTime = Date.now()
501
+
502
+ try {
503
+ if (verifyBefore) {
504
+ const provider = getProvider(proof.metadata.system)
505
+ if (!provider) {
506
+ throw new Error(`No provider for system: ${proof.metadata.system}`)
507
+ }
508
+ const valid = await provider.verifyProof(proof)
509
+ if (!valid) {
510
+ throw new Error('Proof verification failed')
511
+ }
512
+ }
513
+
514
+ verifiedProofs[index] = proof
515
+ stepResults[index] = {
516
+ success: true,
517
+ proof,
518
+ timeMs: Date.now() - stepStartTime,
519
+ depth: 0,
520
+ }
521
+ } catch (error) {
522
+ const errorMsg = error instanceof Error ? error.message : 'Unknown error'
523
+ errors.push(`Proof ${proof.id}: ${errorMsg}`)
524
+ stepResults[index] = {
525
+ success: false,
526
+ error: errorMsg,
527
+ timeMs: Date.now() - stepStartTime,
528
+ depth: 0,
529
+ }
530
+ }
531
+
532
+ completedCount++
533
+ onProgress?.({
534
+ step: completedCount,
535
+ totalSteps: proofs.length,
536
+ operation: `Verified ${completedCount}/${proofs.length} proofs`,
537
+ proofId: proof.id,
538
+ elapsedMs: Date.now() - startTime,
539
+ })
540
+ }
541
+ }
542
+
543
+ // Start workers
544
+ const workers = Array.from(
545
+ { length: Math.min(maxConcurrent, proofs.length) },
546
+ () => worker(),
547
+ )
548
+
549
+ // Set up timeout
550
+ const timeout = createTimeout(this._config.timeoutMs)
551
+
552
+ try {
553
+ await Promise.race([
554
+ Promise.all(workers),
555
+ timeout.promise,
556
+ ])
557
+ } catch (error) {
558
+ if (error instanceof Error && error.message.includes('Timeout')) {
559
+ return this.createFailedResult(
560
+ `Aggregation timed out after ${this._config.timeoutMs}ms`,
561
+ startTime,
562
+ stepResults.filter(Boolean),
563
+ retryStats,
564
+ )
565
+ }
566
+ throw error
567
+ } finally {
568
+ timeout.cancel()
569
+ }
570
+
571
+ // Check for errors
572
+ if (errors.length > 0) {
573
+ return this.createFailedResult(
574
+ `${errors.length} proofs failed: ${errors[0]}`,
575
+ startTime,
576
+ stepResults.filter(Boolean),
577
+ retryStats,
578
+ )
579
+ }
580
+
581
+ // Create composed proof
582
+ const validProofs = verifiedProofs.filter(Boolean)
583
+ const composedProof = this.createComposedProof(
584
+ validProofs,
585
+ Strategy.PARALLEL,
586
+ startTime,
587
+ )
588
+
589
+ return {
590
+ success: true,
591
+ aggregatedProof: computeProofHash(validProofs),
592
+ metrics: {
593
+ inputProofCount: proofs.length,
594
+ outputProofSize: composedProof.proofs.length,
595
+ timeMs: Date.now() - startTime,
596
+ recursionDepth: 0,
597
+ },
598
+ stepResults: stepResults.filter(Boolean),
599
+ composedProof,
600
+ retries: retryStats,
601
+ }
602
+ }
603
+
604
+ // ─── Recursive Aggregation ─────────────────────────────────────────────────
605
+
606
+ /**
607
+ * Aggregate proofs recursively.
608
+ *
609
+ * Combines proofs using recursive SNARKs (proof-of-proofs).
610
+ * This enables constant-size proofs regardless of input count.
611
+ */
612
+ async aggregateRecursive(options: RecursiveAggregationOptions): Promise<DetailedAggregationResult> {
613
+ const startTime = Date.now()
614
+ const { proofs, getProvider, targetSystem, maxDepth, onProgress, abortSignal } = options
615
+ const stepResults: AggregationStepResult[] = []
616
+ const retryStats = { attempted: 0, succeeded: 0, failed: 0 }
617
+
618
+ if (this._config.verbose) {
619
+ console.log(`[Aggregator] Recursive aggregation of ${proofs.length} proofs (target: ${targetSystem}, maxDepth: ${maxDepth})`)
620
+ }
621
+
622
+ // Validate inputs
623
+ if (proofs.length === 0) {
624
+ return this.createFailedResult('No proofs to aggregate', startTime, stepResults, retryStats)
625
+ }
626
+
627
+ if (maxDepth > this._config.maxRecursionDepth) {
628
+ return this.createFailedResult(
629
+ `Max depth ${maxDepth} exceeds limit ${this._config.maxRecursionDepth}`,
630
+ startTime,
631
+ stepResults,
632
+ retryStats,
633
+ )
634
+ }
635
+
636
+ const provider = getProvider(targetSystem)
637
+ if (!provider) {
638
+ return this.createFailedResult(
639
+ `No provider for target system: ${targetSystem}`,
640
+ startTime,
641
+ stepResults,
642
+ retryStats,
643
+ )
644
+ }
645
+
646
+ // Check if provider supports recursion
647
+ if (!provider.capabilities.supportsRecursion) {
648
+ return this.createFailedResult(
649
+ `Provider for ${targetSystem} does not support recursion`,
650
+ startTime,
651
+ stepResults,
652
+ retryStats,
653
+ )
654
+ }
655
+
656
+ // Recursive aggregation loop
657
+ let currentProofs = [...proofs]
658
+ let currentDepth = 0
659
+
660
+ while (currentProofs.length > 1 && currentDepth < maxDepth) {
661
+ if (abortSignal?.aborted) {
662
+ return this.createFailedResult('Aggregation aborted', startTime, stepResults, retryStats)
663
+ }
664
+
665
+ const stepStartTime = Date.now()
666
+ currentDepth++
667
+
668
+ onProgress?.({
669
+ step: currentDepth,
670
+ totalSteps: maxDepth,
671
+ operation: `Recursive merge depth ${currentDepth}: ${currentProofs.length} proofs`,
672
+ elapsedMs: Date.now() - startTime,
673
+ })
674
+
675
+ // Pair up proofs for recursive merging
676
+ const pairs: SingleProof[][] = []
677
+ for (let i = 0; i < currentProofs.length; i += 2) {
678
+ if (i + 1 < currentProofs.length) {
679
+ pairs.push([currentProofs[i], currentProofs[i + 1]])
680
+ } else {
681
+ pairs.push([currentProofs[i]])
682
+ }
683
+ }
684
+
685
+ // Merge pairs
686
+ const mergedProofs: SingleProof[] = []
687
+
688
+ for (const pair of pairs) {
689
+ if (pair.length === 1) {
690
+ // Odd proof out - pass through
691
+ mergedProofs.push(pair[0])
692
+ continue
693
+ }
694
+
695
+ // Simulate recursive proof merge
696
+ // In real implementation, this would use the provider's recursive proving
697
+ const mergedProof = await this.simulateRecursiveMerge(pair, targetSystem, currentDepth)
698
+ mergedProofs.push(mergedProof)
699
+ }
700
+
701
+ stepResults.push({
702
+ success: true,
703
+ timeMs: Date.now() - stepStartTime,
704
+ depth: currentDepth,
705
+ })
706
+
707
+ currentProofs = mergedProofs
708
+
709
+ if (this._config.verbose) {
710
+ console.log(`[Aggregator] Depth ${currentDepth}: ${pairs.length} pairs -> ${mergedProofs.length} proofs`)
711
+ }
712
+ }
713
+
714
+ // Create final composed proof
715
+ const composedProof = this.createComposedProof(
716
+ currentProofs,
717
+ Strategy.RECURSIVE,
718
+ startTime,
719
+ )
720
+
721
+ return {
722
+ success: true,
723
+ aggregatedProof: computeProofHash(currentProofs),
724
+ metrics: {
725
+ inputProofCount: proofs.length,
726
+ outputProofSize: currentProofs.length,
727
+ timeMs: Date.now() - startTime,
728
+ recursionDepth: currentDepth,
729
+ },
730
+ stepResults,
731
+ composedProof,
732
+ retries: retryStats,
733
+ }
734
+ }
735
+
736
+ private async simulateRecursiveMerge(
737
+ proofs: SingleProof[],
738
+ targetSystem: ProofSystem,
739
+ depth: number,
740
+ ): Promise<SingleProof> {
741
+ // Simulate recursive SNARK merge
742
+ // In production, this would use actual recursive proving
743
+ await delay(proofs.length * 50)
744
+
745
+ const combinedInputs = proofs.flatMap(p => p.publicInputs)
746
+ const proofBytes = randomBytes(256)
747
+
748
+ return {
749
+ id: generateId(`recursive-${depth}`),
750
+ proof: `0x${bytesToHex(proofBytes)}`,
751
+ publicInputs: combinedInputs.slice(0, 10) as HexString[],
752
+ metadata: {
753
+ system: targetSystem,
754
+ systemVersion: '1.0.0',
755
+ circuitId: 'recursive_merge',
756
+ circuitVersion: '1.0.0',
757
+ generatedAt: Date.now(),
758
+ proofSizeBytes: proofBytes.length,
759
+ },
760
+ }
761
+ }
762
+
763
+ // ─── Batch Aggregation ─────────────────────────────────────────────────────
764
+
765
+ /**
766
+ * Aggregate proofs using batch verification.
767
+ *
768
+ * Groups proofs by system and uses batch verification where supported.
769
+ */
770
+ async aggregateBatch(
771
+ proofs: SingleProof[],
772
+ getProvider: (system: ProofSystem) => ComposableProofProvider | undefined,
773
+ onProgress?: AggregationProgressCallback,
774
+ ): Promise<DetailedAggregationResult> {
775
+ const startTime = Date.now()
776
+ const stepResults: AggregationStepResult[] = []
777
+ const retryStats = { attempted: 0, succeeded: 0, failed: 0 }
778
+
779
+ if (this._config.verbose) {
780
+ console.log(`[Aggregator] Batch aggregation of ${proofs.length} proofs`)
781
+ }
782
+
783
+ // Group proofs by system
784
+ const groupedBySystem = new Map<ProofSystem, SingleProof[]>()
785
+ for (const proof of proofs) {
786
+ const existing = groupedBySystem.get(proof.metadata.system) || []
787
+ existing.push(proof)
788
+ groupedBySystem.set(proof.metadata.system, existing)
789
+ }
790
+
791
+ if (this._config.verbose) {
792
+ console.log(`[Aggregator] Grouped into ${groupedBySystem.size} systems`)
793
+ }
794
+
795
+ const verifiedProofs: SingleProof[] = []
796
+ let currentStep = 0
797
+ const totalSteps = groupedBySystem.size
798
+
799
+ for (const [system, systemProofs] of groupedBySystem) {
800
+ currentStep++
801
+ const stepStartTime = Date.now()
802
+
803
+ onProgress?.({
804
+ step: currentStep,
805
+ totalSteps,
806
+ operation: `Batch verifying ${systemProofs.length} ${system} proofs`,
807
+ elapsedMs: Date.now() - startTime,
808
+ })
809
+
810
+ const provider = getProvider(system)
811
+ if (!provider) {
812
+ stepResults.push({
813
+ success: false,
814
+ error: `No provider for system: ${system}`,
815
+ timeMs: Date.now() - stepStartTime,
816
+ depth: 0,
817
+ })
818
+ continue
819
+ }
820
+
821
+ // Use batch verification if available
822
+ if (provider.verifyBatch) {
823
+ try {
824
+ const results = await provider.verifyBatch(systemProofs)
825
+ const validProofs = systemProofs.filter((_, i) => results[i])
826
+ verifiedProofs.push(...validProofs)
827
+
828
+ if (validProofs.length < systemProofs.length) {
829
+ const failed = systemProofs.length - validProofs.length
830
+ stepResults.push({
831
+ success: false,
832
+ error: `${failed} proofs failed batch verification`,
833
+ timeMs: Date.now() - stepStartTime,
834
+ depth: 0,
835
+ })
836
+ } else {
837
+ stepResults.push({
838
+ success: true,
839
+ timeMs: Date.now() - stepStartTime,
840
+ depth: 0,
841
+ })
842
+ }
843
+ } catch (error) {
844
+ stepResults.push({
845
+ success: false,
846
+ error: error instanceof Error ? error.message : 'Unknown error',
847
+ timeMs: Date.now() - stepStartTime,
848
+ depth: 0,
849
+ })
850
+ }
851
+ } else {
852
+ // Fall back to individual verification
853
+ for (const proof of systemProofs) {
854
+ try {
855
+ const valid = await provider.verifyProof(proof)
856
+ if (valid) {
857
+ verifiedProofs.push(proof)
858
+ }
859
+ } catch {
860
+ // Skip invalid proofs
861
+ }
862
+ }
863
+ stepResults.push({
864
+ success: true,
865
+ timeMs: Date.now() - stepStartTime,
866
+ depth: 0,
867
+ })
868
+ }
869
+ }
870
+
871
+ // Create composed proof
872
+ const composedProof = this.createComposedProof(
873
+ verifiedProofs,
874
+ Strategy.BATCH,
875
+ startTime,
876
+ )
877
+
878
+ return {
879
+ success: verifiedProofs.length === proofs.length,
880
+ aggregatedProof: computeProofHash(verifiedProofs),
881
+ metrics: {
882
+ inputProofCount: proofs.length,
883
+ outputProofSize: verifiedProofs.length,
884
+ timeMs: Date.now() - startTime,
885
+ recursionDepth: 0,
886
+ },
887
+ stepResults,
888
+ composedProof,
889
+ retries: retryStats,
890
+ }
891
+ }
892
+
893
+ // ─── Cross-System Aggregation ──────────────────────────────────────────────
894
+
895
+ /**
896
+ * Link proofs from different systems.
897
+ *
898
+ * Creates a cryptographic link between proofs from different ZK systems.
899
+ */
900
+ createCrossSystemLink(
901
+ sourceProof: SingleProof,
902
+ targetProof: SingleProof,
903
+ ): HexString {
904
+ // Compute a link hash combining both proofs
905
+ const combinedData = sourceProof.proof + targetProof.proof
906
+ let hash = 0
907
+ for (let i = 0; i < combinedData.length; i++) {
908
+ const char = combinedData.charCodeAt(i)
909
+ hash = ((hash << 5) - hash) + char
910
+ hash = hash & hash
911
+ }
912
+ return `0x${Math.abs(hash).toString(16).padStart(64, '0')}` as HexString
913
+ }
914
+
915
+ /**
916
+ * Verify a cross-system link.
917
+ */
918
+ verifyCrossSystemLink(
919
+ sourceProof: SingleProof,
920
+ targetProof: SingleProof,
921
+ linkHash: HexString,
922
+ ): boolean {
923
+ const computedLink = this.createCrossSystemLink(sourceProof, targetProof)
924
+ return computedLink === linkHash
925
+ }
926
+
927
+ // ─── Helper Methods ────────────────────────────────────────────────────────
928
+
929
+ private createComposedProof(
930
+ proofs: SingleProof[],
931
+ strategy: ProofAggregationStrategy,
932
+ startTime: number,
933
+ ): ComposedProof {
934
+ const systems = [...new Set(proofs.map(p => p.metadata.system))]
935
+
936
+ return {
937
+ id: generateId('composed'),
938
+ proofs,
939
+ strategy,
940
+ status: ComposedProofStatus.VERIFIED,
941
+ combinedPublicInputs: proofs.flatMap(p => p.publicInputs),
942
+ compositionMetadata: {
943
+ proofCount: proofs.length,
944
+ systems,
945
+ compositionTimeMs: Date.now() - startTime,
946
+ success: true,
947
+ inputHash: computeProofHash(proofs),
948
+ },
949
+ verificationHints: this.computeVerificationHints(proofs, strategy),
950
+ }
951
+ }
952
+
953
+ private computeVerificationHints(
954
+ proofs: SingleProof[],
955
+ strategy: ProofAggregationStrategy,
956
+ ): VerificationHints {
957
+ const verificationOrder = proofs.map(p => p.id)
958
+
959
+ const systemGroups = new Map<ProofSystem, string[]>()
960
+ for (const proof of proofs) {
961
+ const existing = systemGroups.get(proof.metadata.system) || []
962
+ existing.push(proof.id)
963
+ systemGroups.set(proof.metadata.system, existing)
964
+ }
965
+ const parallelGroups = Array.from(systemGroups.values())
966
+
967
+ return {
968
+ verificationOrder,
969
+ parallelGroups,
970
+ estimatedTimeMs: proofs.length * 100,
971
+ estimatedCost: BigInt(proofs.length * 100000),
972
+ supportsBatchVerification: strategy === Strategy.BATCH,
973
+ }
974
+ }
975
+
976
+ private createFailedResult(
977
+ error: string,
978
+ startTime: number,
979
+ stepResults: AggregationStepResult[],
980
+ retries: { attempted: number; succeeded: number; failed: number },
981
+ ): DetailedAggregationResult {
982
+ return {
983
+ success: false,
984
+ error,
985
+ metrics: {
986
+ inputProofCount: 0,
987
+ outputProofSize: 0,
988
+ timeMs: Date.now() - startTime,
989
+ recursionDepth: 0,
990
+ },
991
+ stepResults,
992
+ retries,
993
+ }
994
+ }
995
+
996
+ // ─── Events ────────────────────────────────────────────────────────────────
997
+
998
+ addEventListener(listener: CompositionEventListener): () => void {
999
+ this._eventListeners.add(listener)
1000
+ return () => this._eventListeners.delete(listener)
1001
+ }
1002
+
1003
+ removeEventListener(listener: CompositionEventListener): void {
1004
+ this._eventListeners.delete(listener)
1005
+ }
1006
+
1007
+ private emitEvent(event: CompositionEvent): void {
1008
+ for (const listener of this._eventListeners) {
1009
+ try {
1010
+ listener(event)
1011
+ } catch {
1012
+ // Ignore listener errors
1013
+ }
1014
+ }
1015
+ }
1016
+ }
1017
+
1018
+ // ─── Factory Function ────────────────────────────────────────────────────────
1019
+
1020
+ /**
1021
+ * Create a proof aggregator with optional configuration
1022
+ */
1023
+ export function createProofAggregator(config?: Partial<AggregatorConfig>): ProofAggregator {
1024
+ return new ProofAggregator(config)
1025
+ }
1026
+
1027
+ // ─── Export Default Configuration ────────────────────────────────────────────
1028
+
1029
+ export { DEFAULT_AGGREGATOR_CONFIG }