@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.
- package/LICENSE +21 -0
- package/README.md +267 -0
- package/dist/{TransportWebUSB-TQ7WZ4LE.mjs → TransportWebUSB-YQMAGJAJ.mjs} +12 -9
- package/dist/browser.d.mts +10 -4
- package/dist/browser.d.ts +10 -4
- package/dist/browser.js +48874 -18336
- package/dist/browser.mjs +674 -48
- package/dist/chunk-4GRJ5MAW.mjs +152 -0
- package/dist/chunk-5D7A3L3W.mjs +717 -0
- package/dist/chunk-64AYA5F5.mjs +7834 -0
- package/dist/chunk-GMDGB22A.mjs +379 -0
- package/dist/chunk-I534WKN7.mjs +328 -0
- package/dist/chunk-IBZVA5Y7.mjs +1003 -0
- package/dist/chunk-PRRZAWJE.mjs +223 -0
- package/dist/{chunk-UJCSKKID.mjs → chunk-XGB3TDIC.mjs} +13 -1
- package/dist/chunk-YWGJ77A2.mjs +33806 -0
- package/dist/{chunk-6WGN57S2.mjs → chunk-Z3K7W5S3.mjs} +48 -0
- package/dist/constants-LHAAUC2T.mjs +51 -0
- package/dist/dist-2OGQ7FED.mjs +3957 -0
- package/dist/dist-IFHPYLDX.mjs +254 -0
- package/dist/fulfillment_proof-ANHVPKTB.mjs +21 -0
- package/dist/funding_proof-ICFZ5LHY.mjs +21 -0
- package/dist/index-DXh2IGkz.d.ts +24681 -0
- package/dist/index-DeE1ZzA4.d.mts +24681 -0
- package/dist/index.d.mts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.js +48676 -17318
- package/dist/index.mjs +583 -19
- package/dist/interface-Bf7w1PLW.d.mts +679 -0
- package/dist/interface-Bf7w1PLW.d.ts +679 -0
- package/dist/{noir-DKfEzWy9.d.mts → noir-kzbLVTei.d.mts} +31 -21
- package/dist/{noir-DKfEzWy9.d.ts → noir-kzbLVTei.d.ts} +31 -21
- package/dist/proofs/halo2.d.mts +151 -0
- package/dist/proofs/halo2.d.ts +151 -0
- package/dist/proofs/halo2.js +350 -0
- package/dist/proofs/halo2.mjs +11 -0
- package/dist/proofs/kimchi.d.mts +160 -0
- package/dist/proofs/kimchi.d.ts +160 -0
- package/dist/proofs/kimchi.js +431 -0
- package/dist/proofs/kimchi.mjs +13 -0
- package/dist/proofs/noir.d.mts +1 -1
- package/dist/proofs/noir.d.ts +1 -1
- package/dist/proofs/noir.js +74 -18
- package/dist/proofs/noir.mjs +84 -24
- package/dist/solana-U3MEGU7W.mjs +280 -0
- package/dist/validity_proof-3POXLPNY.mjs +21 -0
- package/package.json +54 -21
- package/src/adapters/index.ts +41 -0
- package/src/adapters/jupiter.ts +571 -0
- package/src/adapters/near-intents.ts +135 -0
- package/src/advisor/advisor.ts +653 -0
- package/src/advisor/index.ts +54 -0
- package/src/advisor/tools.ts +303 -0
- package/src/advisor/types.ts +164 -0
- package/src/chains/ethereum/announcement.ts +536 -0
- package/src/chains/ethereum/bnb-optimizations.ts +474 -0
- package/src/chains/ethereum/commitment.ts +522 -0
- package/src/chains/ethereum/constants.ts +462 -0
- package/src/chains/ethereum/deployment.ts +596 -0
- package/src/chains/ethereum/gas-estimation.ts +538 -0
- package/src/chains/ethereum/index.ts +268 -0
- package/src/chains/ethereum/optimizations.ts +614 -0
- package/src/chains/ethereum/privacy-adapter.ts +855 -0
- package/src/chains/ethereum/registry.ts +584 -0
- package/src/chains/ethereum/rpc.ts +905 -0
- package/src/chains/ethereum/stealth.ts +491 -0
- package/src/chains/ethereum/token.ts +790 -0
- package/src/chains/ethereum/transfer.ts +637 -0
- package/src/chains/ethereum/types.ts +456 -0
- package/src/chains/ethereum/viewing-key.ts +455 -0
- package/src/chains/near/commitment.ts +608 -0
- package/src/chains/near/constants.ts +284 -0
- package/src/chains/near/function-call.ts +871 -0
- package/src/chains/near/history.ts +654 -0
- package/src/chains/near/implicit-account.ts +840 -0
- package/src/chains/near/index.ts +393 -0
- package/src/chains/near/native-transfer.ts +658 -0
- package/src/chains/near/nep141.ts +775 -0
- package/src/chains/near/privacy-adapter.ts +889 -0
- package/src/chains/near/resolver.ts +971 -0
- package/src/chains/near/rpc.ts +1016 -0
- package/src/chains/near/stealth.ts +419 -0
- package/src/chains/near/types.ts +317 -0
- package/src/chains/near/viewing-key.ts +876 -0
- package/src/chains/solana/anchor-transfer.ts +386 -0
- package/src/chains/solana/commitment.ts +577 -0
- package/src/chains/solana/constants.ts +126 -12
- package/src/chains/solana/ephemeral-keys.ts +543 -0
- package/src/chains/solana/index.ts +276 -1
- package/src/chains/solana/key-derivation.ts +418 -0
- package/src/chains/solana/kit-compat.ts +334 -0
- package/src/chains/solana/optimizations.ts +560 -0
- package/src/chains/solana/privacy-adapter.ts +605 -0
- package/src/chains/solana/providers/generic.ts +201 -0
- package/src/chains/solana/providers/helius-enhanced-types.ts +336 -0
- package/src/chains/solana/providers/helius-enhanced.ts +623 -0
- package/src/chains/solana/providers/helius.ts +402 -0
- package/src/chains/solana/providers/index.ts +85 -0
- package/src/chains/solana/providers/interface.ts +221 -0
- package/src/chains/solana/providers/quicknode.ts +409 -0
- package/src/chains/solana/providers/triton.ts +426 -0
- package/src/chains/solana/providers/webhook.ts +790 -0
- package/src/chains/solana/rpc-client.ts +1150 -0
- package/src/chains/solana/scan.ts +170 -73
- package/src/chains/solana/sol-transfer.ts +732 -0
- package/src/chains/solana/spl-transfer.ts +886 -0
- package/src/chains/solana/stealth-scanner.ts +703 -0
- package/src/chains/solana/sunspot-verifier.ts +453 -0
- package/src/chains/solana/transaction-builder.ts +755 -0
- package/src/chains/solana/transfer.ts +74 -5
- package/src/chains/solana/types.ts +77 -7
- package/src/chains/solana/utils.ts +110 -0
- package/src/chains/solana/viewing-key.ts +807 -0
- package/src/compliance/fireblocks.ts +921 -0
- package/src/compliance/index.ts +37 -0
- package/src/compliance/range-sas.ts +956 -0
- package/src/config/endpoints.ts +100 -0
- package/src/crypto.ts +11 -8
- package/src/errors.ts +82 -0
- package/src/evm/erc4337-relayer.ts +830 -0
- package/src/evm/index.ts +47 -0
- package/src/fees/calculator.ts +396 -0
- package/src/fees/index.ts +87 -0
- package/src/fees/near-contract.ts +429 -0
- package/src/fees/types.ts +268 -0
- package/src/index.ts +785 -1
- package/src/intent.ts +6 -3
- package/src/logger.ts +324 -0
- package/src/network/index.ts +80 -0
- package/src/network/proxy.ts +691 -0
- package/src/optimizations/index.ts +541 -0
- package/src/oracle/types.ts +1 -0
- package/src/privacy-backends/arcium-types.ts +727 -0
- package/src/privacy-backends/arcium.ts +719 -0
- package/src/privacy-backends/combined-privacy.ts +866 -0
- package/src/privacy-backends/cspl-token.ts +595 -0
- package/src/privacy-backends/cspl-types.ts +512 -0
- package/src/privacy-backends/cspl.ts +907 -0
- package/src/privacy-backends/health.ts +488 -0
- package/src/privacy-backends/inco-types.ts +323 -0
- package/src/privacy-backends/inco.ts +616 -0
- package/src/privacy-backends/index.ts +336 -0
- package/src/privacy-backends/interface.ts +906 -0
- package/src/privacy-backends/lru-cache.ts +343 -0
- package/src/privacy-backends/magicblock.ts +458 -0
- package/src/privacy-backends/mock.ts +258 -0
- package/src/privacy-backends/privacycash-types.ts +278 -0
- package/src/privacy-backends/privacycash.ts +456 -0
- package/src/privacy-backends/private-swap.ts +570 -0
- package/src/privacy-backends/rate-limiter.ts +683 -0
- package/src/privacy-backends/registry.ts +690 -0
- package/src/privacy-backends/router.ts +626 -0
- package/src/privacy-backends/shadowwire.ts +449 -0
- package/src/privacy-backends/sip-native.ts +256 -0
- package/src/privacy-logger.ts +191 -0
- package/src/production-safety.ts +373 -0
- package/src/proofs/aggregator.ts +1029 -0
- package/src/proofs/browser-composer.ts +1150 -0
- package/src/proofs/browser.ts +113 -25
- package/src/proofs/cache/index.ts +127 -0
- package/src/proofs/cache/interface.ts +545 -0
- package/src/proofs/cache/key-generator.ts +188 -0
- package/src/proofs/cache/lru-cache.ts +481 -0
- package/src/proofs/cache/multi-tier-cache.ts +575 -0
- package/src/proofs/cache/persistent-cache.ts +788 -0
- package/src/proofs/compliance-proof.ts +872 -0
- package/src/proofs/composer/base.ts +923 -0
- package/src/proofs/composer/index.ts +25 -0
- package/src/proofs/composer/interface.ts +518 -0
- package/src/proofs/composer/types.ts +383 -0
- package/src/proofs/converters/halo2.ts +452 -0
- package/src/proofs/converters/index.ts +208 -0
- package/src/proofs/converters/interface.ts +363 -0
- package/src/proofs/converters/kimchi.ts +462 -0
- package/src/proofs/converters/noir.ts +451 -0
- package/src/proofs/fallback.ts +888 -0
- package/src/proofs/halo2.ts +42 -0
- package/src/proofs/index.ts +471 -0
- package/src/proofs/interface.ts +13 -0
- package/src/proofs/kimchi.ts +42 -0
- package/src/proofs/lazy.ts +1004 -0
- package/src/proofs/mock.ts +25 -1
- package/src/proofs/noir.ts +111 -30
- package/src/proofs/orchestrator.ts +960 -0
- package/src/proofs/parallel/concurrency.ts +297 -0
- package/src/proofs/parallel/dependency-graph.ts +602 -0
- package/src/proofs/parallel/executor.ts +420 -0
- package/src/proofs/parallel/index.ts +131 -0
- package/src/proofs/parallel/interface.ts +685 -0
- package/src/proofs/parallel/worker-pool.ts +644 -0
- package/src/proofs/providers/halo2.ts +560 -0
- package/src/proofs/providers/index.ts +34 -0
- package/src/proofs/providers/kimchi.ts +641 -0
- package/src/proofs/validator.ts +881 -0
- package/src/proofs/verifier.ts +867 -0
- package/src/quantum/index.ts +112 -0
- package/src/quantum/winternitz-vault.ts +639 -0
- package/src/quantum/wots.ts +611 -0
- package/src/settlement/backends/direct-chain.ts +1 -0
- package/src/settlement/index.ts +9 -0
- package/src/settlement/router.ts +732 -46
- package/src/solana/index.ts +72 -0
- package/src/solana/jito-relayer.ts +687 -0
- package/src/solana/noir-verifier-types.ts +430 -0
- package/src/solana/noir-verifier.ts +816 -0
- package/src/stealth/address-derivation.ts +193 -0
- package/src/stealth/ed25519.ts +431 -0
- package/src/stealth/index.ts +233 -0
- package/src/stealth/meta-address.ts +221 -0
- package/src/stealth/secp256k1.ts +368 -0
- package/src/stealth/utils.ts +194 -0
- package/src/stealth.ts +50 -1504
- package/src/surveillance/algorithms/address-reuse.ts +143 -0
- package/src/surveillance/algorithms/cluster.ts +247 -0
- package/src/surveillance/algorithms/exchange.ts +295 -0
- package/src/surveillance/algorithms/temporal.ts +337 -0
- package/src/surveillance/analyzer.ts +442 -0
- package/src/surveillance/index.ts +64 -0
- package/src/surveillance/scoring.ts +372 -0
- package/src/surveillance/types.ts +264 -0
- package/src/sync/index.ts +106 -0
- package/src/sync/manager.ts +504 -0
- package/src/sync/mock-provider.ts +318 -0
- package/src/sync/oblivious.ts +625 -0
- package/src/tokens/index.ts +15 -0
- package/src/tokens/registry.ts +301 -0
- package/src/utils/deprecation.ts +94 -0
- package/src/utils/index.ts +9 -0
- package/src/wallet/ethereum/index.ts +68 -0
- package/src/wallet/ethereum/metamask-privacy.ts +420 -0
- package/src/wallet/ethereum/multi-wallet.ts +646 -0
- package/src/wallet/ethereum/privacy-adapter.ts +700 -0
- package/src/wallet/ethereum/types.ts +3 -1
- package/src/wallet/ethereum/walletconnect-adapter.ts +675 -0
- package/src/wallet/hardware/index.ts +10 -0
- package/src/wallet/hardware/ledger-privacy.ts +414 -0
- package/src/wallet/index.ts +71 -0
- package/src/wallet/near/adapter.ts +626 -0
- package/src/wallet/near/index.ts +86 -0
- package/src/wallet/near/meteor-wallet.ts +1153 -0
- package/src/wallet/near/my-near-wallet.ts +790 -0
- package/src/wallet/near/wallet-selector.ts +702 -0
- package/src/wallet/solana/adapter.ts +6 -4
- package/src/wallet/solana/index.ts +13 -0
- package/src/wallet/solana/privacy-adapter.ts +567 -0
- package/src/wallet/sui/types.ts +6 -4
- package/src/zcash/rpc-client.ts +13 -6
- package/dist/chunk-3INS3PR5.mjs +0 -884
- package/dist/chunk-3OVABDRH.mjs +0 -17096
- package/dist/chunk-DLDWZFYC.mjs +0 -1495
- package/dist/chunk-E6SZWREQ.mjs +0 -57
- package/dist/chunk-G33LB27A.mjs +0 -16166
- package/dist/chunk-HGU6HZRC.mjs +0 -231
- package/dist/chunk-L2K34JCU.mjs +0 -1496
- package/dist/chunk-SN4ZDTVW.mjs +0 -16166
- package/dist/constants-VOI7BSLK.mjs +0 -27
- package/dist/index-BYZbDjal.d.ts +0 -11390
- package/dist/index-CHB3KuOB.d.mts +0 -11859
- package/dist/index-CzWPI6Le.d.ts +0 -11859
- package/dist/index-xbWjohNq.d.mts +0 -11390
- package/dist/solana-5EMCTPTS.mjs +0 -46
- 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 }
|