@sip-protocol/sdk 0.7.3 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (263) hide show
  1. package/README.md +267 -0
  2. package/dist/{TransportWebUSB-TQ7WZ4LE.mjs → TransportWebUSB-YQMAGJAJ.mjs} +12 -9
  3. package/dist/browser.d.mts +10 -4
  4. package/dist/browser.d.ts +10 -4
  5. package/dist/browser.js +47556 -19603
  6. package/dist/browser.mjs +628 -48
  7. package/dist/chunk-4GRJ5MAW.mjs +152 -0
  8. package/dist/chunk-5D7A3L3W.mjs +717 -0
  9. package/dist/chunk-64AYA5F5.mjs +7834 -0
  10. package/dist/chunk-GMDGB22A.mjs +379 -0
  11. package/dist/chunk-I534WKN7.mjs +328 -0
  12. package/dist/chunk-IBZVA5Y7.mjs +1003 -0
  13. package/dist/chunk-PRRZAWJE.mjs +223 -0
  14. package/dist/{chunk-UJCSKKID.mjs → chunk-XGB3TDIC.mjs} +13 -1
  15. package/dist/{chunk-3M3HNQCW.mjs → chunk-YWGJ77A2.mjs} +28656 -13103
  16. package/dist/{chunk-6WGN57S2.mjs → chunk-Z3K7W5S3.mjs} +48 -0
  17. package/dist/constants-LHAAUC2T.mjs +51 -0
  18. package/dist/dist-2OGQ7FED.mjs +3957 -0
  19. package/dist/dist-IFHPYLDX.mjs +254 -0
  20. package/dist/fulfillment_proof-ANHVPKTB.mjs +21 -0
  21. package/dist/funding_proof-ICFZ5LHY.mjs +21 -0
  22. package/dist/{index-DIBZHOOQ.d.ts → index-DXh2IGkz.d.ts} +21239 -10304
  23. package/dist/{index-8MQz13eJ.d.mts → index-DeE1ZzA4.d.mts} +21239 -10304
  24. package/dist/index.d.mts +9 -3
  25. package/dist/index.d.ts +9 -3
  26. package/dist/index.js +48396 -19623
  27. package/dist/index.mjs +537 -19
  28. package/dist/interface-Bf7w1PLW.d.mts +679 -0
  29. package/dist/interface-Bf7w1PLW.d.ts +679 -0
  30. package/dist/{noir-DKfEzWy9.d.mts → noir-kzbLVTei.d.mts} +31 -21
  31. package/dist/{noir-DKfEzWy9.d.ts → noir-kzbLVTei.d.ts} +31 -21
  32. package/dist/proofs/halo2.d.mts +151 -0
  33. package/dist/proofs/halo2.d.ts +151 -0
  34. package/dist/proofs/halo2.js +350 -0
  35. package/dist/proofs/halo2.mjs +11 -0
  36. package/dist/proofs/kimchi.d.mts +160 -0
  37. package/dist/proofs/kimchi.d.ts +160 -0
  38. package/dist/proofs/kimchi.js +431 -0
  39. package/dist/proofs/kimchi.mjs +13 -0
  40. package/dist/proofs/noir.d.mts +1 -1
  41. package/dist/proofs/noir.d.ts +1 -1
  42. package/dist/proofs/noir.js +74 -18
  43. package/dist/proofs/noir.mjs +84 -24
  44. package/dist/solana-U3MEGU7W.mjs +280 -0
  45. package/dist/validity_proof-3POXLPNY.mjs +21 -0
  46. package/package.json +44 -11
  47. package/src/adapters/index.ts +41 -0
  48. package/src/adapters/jupiter.ts +571 -0
  49. package/src/adapters/near-intents.ts +135 -0
  50. package/src/advisor/advisor.ts +653 -0
  51. package/src/advisor/index.ts +54 -0
  52. package/src/advisor/tools.ts +303 -0
  53. package/src/advisor/types.ts +164 -0
  54. package/src/chains/ethereum/announcement.ts +536 -0
  55. package/src/chains/ethereum/bnb-optimizations.ts +474 -0
  56. package/src/chains/ethereum/commitment.ts +522 -0
  57. package/src/chains/ethereum/constants.ts +462 -0
  58. package/src/chains/ethereum/deployment.ts +596 -0
  59. package/src/chains/ethereum/gas-estimation.ts +538 -0
  60. package/src/chains/ethereum/index.ts +268 -0
  61. package/src/chains/ethereum/optimizations.ts +614 -0
  62. package/src/chains/ethereum/privacy-adapter.ts +855 -0
  63. package/src/chains/ethereum/registry.ts +584 -0
  64. package/src/chains/ethereum/rpc.ts +905 -0
  65. package/src/chains/ethereum/stealth.ts +491 -0
  66. package/src/chains/ethereum/token.ts +790 -0
  67. package/src/chains/ethereum/transfer.ts +637 -0
  68. package/src/chains/ethereum/types.ts +456 -0
  69. package/src/chains/ethereum/viewing-key.ts +455 -0
  70. package/src/chains/near/commitment.ts +608 -0
  71. package/src/chains/near/constants.ts +284 -0
  72. package/src/chains/near/function-call.ts +871 -0
  73. package/src/chains/near/history.ts +654 -0
  74. package/src/chains/near/implicit-account.ts +840 -0
  75. package/src/chains/near/index.ts +393 -0
  76. package/src/chains/near/native-transfer.ts +658 -0
  77. package/src/chains/near/nep141.ts +775 -0
  78. package/src/chains/near/privacy-adapter.ts +889 -0
  79. package/src/chains/near/resolver.ts +971 -0
  80. package/src/chains/near/rpc.ts +1016 -0
  81. package/src/chains/near/stealth.ts +419 -0
  82. package/src/chains/near/types.ts +317 -0
  83. package/src/chains/near/viewing-key.ts +876 -0
  84. package/src/chains/solana/anchor-transfer.ts +386 -0
  85. package/src/chains/solana/commitment.ts +577 -0
  86. package/src/chains/solana/constants.ts +126 -12
  87. package/src/chains/solana/ephemeral-keys.ts +543 -0
  88. package/src/chains/solana/index.ts +252 -1
  89. package/src/chains/solana/key-derivation.ts +418 -0
  90. package/src/chains/solana/kit-compat.ts +334 -0
  91. package/src/chains/solana/optimizations.ts +560 -0
  92. package/src/chains/solana/privacy-adapter.ts +605 -0
  93. package/src/chains/solana/providers/generic.ts +47 -6
  94. package/src/chains/solana/providers/helius-enhanced-types.ts +336 -0
  95. package/src/chains/solana/providers/helius-enhanced.ts +623 -0
  96. package/src/chains/solana/providers/helius.ts +186 -33
  97. package/src/chains/solana/providers/index.ts +31 -0
  98. package/src/chains/solana/providers/interface.ts +61 -18
  99. package/src/chains/solana/providers/quicknode.ts +409 -0
  100. package/src/chains/solana/providers/triton.ts +426 -0
  101. package/src/chains/solana/providers/webhook.ts +338 -67
  102. package/src/chains/solana/rpc-client.ts +1150 -0
  103. package/src/chains/solana/scan.ts +83 -66
  104. package/src/chains/solana/sol-transfer.ts +732 -0
  105. package/src/chains/solana/spl-transfer.ts +886 -0
  106. package/src/chains/solana/stealth-scanner.ts +703 -0
  107. package/src/chains/solana/sunspot-verifier.ts +453 -0
  108. package/src/chains/solana/transaction-builder.ts +755 -0
  109. package/src/chains/solana/transfer.ts +74 -5
  110. package/src/chains/solana/types.ts +57 -6
  111. package/src/chains/solana/utils.ts +110 -0
  112. package/src/chains/solana/viewing-key.ts +807 -0
  113. package/src/compliance/fireblocks.ts +921 -0
  114. package/src/compliance/index.ts +23 -0
  115. package/src/compliance/range-sas.ts +398 -33
  116. package/src/config/endpoints.ts +100 -0
  117. package/src/crypto.ts +11 -8
  118. package/src/errors.ts +82 -0
  119. package/src/evm/erc4337-relayer.ts +830 -0
  120. package/src/evm/index.ts +47 -0
  121. package/src/fees/calculator.ts +396 -0
  122. package/src/fees/index.ts +87 -0
  123. package/src/fees/near-contract.ts +429 -0
  124. package/src/fees/types.ts +268 -0
  125. package/src/index.ts +686 -1
  126. package/src/intent.ts +6 -3
  127. package/src/logger.ts +324 -0
  128. package/src/network/index.ts +80 -0
  129. package/src/network/proxy.ts +691 -0
  130. package/src/optimizations/index.ts +541 -0
  131. package/src/oracle/types.ts +1 -0
  132. package/src/privacy-backends/arcium-types.ts +727 -0
  133. package/src/privacy-backends/arcium.ts +719 -0
  134. package/src/privacy-backends/combined-privacy.ts +866 -0
  135. package/src/privacy-backends/cspl-token.ts +595 -0
  136. package/src/privacy-backends/cspl-types.ts +512 -0
  137. package/src/privacy-backends/cspl.ts +907 -0
  138. package/src/privacy-backends/health.ts +488 -0
  139. package/src/privacy-backends/inco-types.ts +323 -0
  140. package/src/privacy-backends/inco.ts +616 -0
  141. package/src/privacy-backends/index.ts +254 -4
  142. package/src/privacy-backends/interface.ts +649 -6
  143. package/src/privacy-backends/lru-cache.ts +343 -0
  144. package/src/privacy-backends/magicblock.ts +458 -0
  145. package/src/privacy-backends/mock.ts +258 -0
  146. package/src/privacy-backends/privacycash.ts +13 -17
  147. package/src/privacy-backends/private-swap.ts +570 -0
  148. package/src/privacy-backends/rate-limiter.ts +683 -0
  149. package/src/privacy-backends/registry.ts +414 -2
  150. package/src/privacy-backends/router.ts +283 -3
  151. package/src/privacy-backends/shadowwire.ts +449 -0
  152. package/src/privacy-backends/sip-native.ts +3 -0
  153. package/src/privacy-logger.ts +191 -0
  154. package/src/production-safety.ts +373 -0
  155. package/src/proofs/aggregator.ts +1029 -0
  156. package/src/proofs/browser-composer.ts +1150 -0
  157. package/src/proofs/browser.ts +113 -25
  158. package/src/proofs/cache/index.ts +127 -0
  159. package/src/proofs/cache/interface.ts +545 -0
  160. package/src/proofs/cache/key-generator.ts +188 -0
  161. package/src/proofs/cache/lru-cache.ts +481 -0
  162. package/src/proofs/cache/multi-tier-cache.ts +575 -0
  163. package/src/proofs/cache/persistent-cache.ts +788 -0
  164. package/src/proofs/compliance-proof.ts +872 -0
  165. package/src/proofs/composer/base.ts +923 -0
  166. package/src/proofs/composer/index.ts +25 -0
  167. package/src/proofs/composer/interface.ts +518 -0
  168. package/src/proofs/composer/types.ts +383 -0
  169. package/src/proofs/converters/halo2.ts +452 -0
  170. package/src/proofs/converters/index.ts +208 -0
  171. package/src/proofs/converters/interface.ts +363 -0
  172. package/src/proofs/converters/kimchi.ts +462 -0
  173. package/src/proofs/converters/noir.ts +451 -0
  174. package/src/proofs/fallback.ts +888 -0
  175. package/src/proofs/halo2.ts +42 -0
  176. package/src/proofs/index.ts +471 -0
  177. package/src/proofs/interface.ts +13 -0
  178. package/src/proofs/kimchi.ts +42 -0
  179. package/src/proofs/lazy.ts +1004 -0
  180. package/src/proofs/mock.ts +25 -1
  181. package/src/proofs/noir.ts +110 -29
  182. package/src/proofs/orchestrator.ts +960 -0
  183. package/src/proofs/parallel/concurrency.ts +297 -0
  184. package/src/proofs/parallel/dependency-graph.ts +602 -0
  185. package/src/proofs/parallel/executor.ts +420 -0
  186. package/src/proofs/parallel/index.ts +131 -0
  187. package/src/proofs/parallel/interface.ts +685 -0
  188. package/src/proofs/parallel/worker-pool.ts +644 -0
  189. package/src/proofs/providers/halo2.ts +560 -0
  190. package/src/proofs/providers/index.ts +34 -0
  191. package/src/proofs/providers/kimchi.ts +641 -0
  192. package/src/proofs/validator.ts +881 -0
  193. package/src/proofs/verifier.ts +867 -0
  194. package/src/quantum/index.ts +112 -0
  195. package/src/quantum/winternitz-vault.ts +639 -0
  196. package/src/quantum/wots.ts +611 -0
  197. package/src/settlement/backends/direct-chain.ts +1 -0
  198. package/src/settlement/index.ts +9 -0
  199. package/src/settlement/router.ts +732 -46
  200. package/src/solana/index.ts +72 -0
  201. package/src/solana/jito-relayer.ts +687 -0
  202. package/src/solana/noir-verifier-types.ts +430 -0
  203. package/src/solana/noir-verifier.ts +816 -0
  204. package/src/stealth/address-derivation.ts +193 -0
  205. package/src/stealth/ed25519.ts +431 -0
  206. package/src/stealth/index.ts +233 -0
  207. package/src/stealth/meta-address.ts +221 -0
  208. package/src/stealth/secp256k1.ts +368 -0
  209. package/src/stealth/utils.ts +194 -0
  210. package/src/stealth.ts +50 -1504
  211. package/src/sync/index.ts +106 -0
  212. package/src/sync/manager.ts +504 -0
  213. package/src/sync/mock-provider.ts +318 -0
  214. package/src/sync/oblivious.ts +625 -0
  215. package/src/tokens/index.ts +15 -0
  216. package/src/tokens/registry.ts +301 -0
  217. package/src/utils/deprecation.ts +94 -0
  218. package/src/utils/index.ts +9 -0
  219. package/src/wallet/ethereum/index.ts +68 -0
  220. package/src/wallet/ethereum/metamask-privacy.ts +420 -0
  221. package/src/wallet/ethereum/multi-wallet.ts +646 -0
  222. package/src/wallet/ethereum/privacy-adapter.ts +700 -0
  223. package/src/wallet/ethereum/types.ts +3 -1
  224. package/src/wallet/ethereum/walletconnect-adapter.ts +675 -0
  225. package/src/wallet/hardware/index.ts +10 -0
  226. package/src/wallet/hardware/ledger-privacy.ts +414 -0
  227. package/src/wallet/index.ts +71 -0
  228. package/src/wallet/near/adapter.ts +626 -0
  229. package/src/wallet/near/index.ts +86 -0
  230. package/src/wallet/near/meteor-wallet.ts +1153 -0
  231. package/src/wallet/near/my-near-wallet.ts +790 -0
  232. package/src/wallet/near/wallet-selector.ts +702 -0
  233. package/src/wallet/solana/adapter.ts +6 -4
  234. package/src/wallet/solana/index.ts +13 -0
  235. package/src/wallet/solana/privacy-adapter.ts +567 -0
  236. package/src/wallet/sui/types.ts +6 -4
  237. package/src/zcash/rpc-client.ts +13 -6
  238. package/dist/chunk-2XIVXWHA.mjs +0 -1930
  239. package/dist/chunk-3INS3PR5.mjs +0 -884
  240. package/dist/chunk-3OVABDRH.mjs +0 -17096
  241. package/dist/chunk-7RFRWDCW.mjs +0 -1504
  242. package/dist/chunk-DLDWZFYC.mjs +0 -1495
  243. package/dist/chunk-E6SZWREQ.mjs +0 -57
  244. package/dist/chunk-F6F73W35.mjs +0 -16166
  245. package/dist/chunk-G33LB27A.mjs +0 -16166
  246. package/dist/chunk-HGU6HZRC.mjs +0 -231
  247. package/dist/chunk-L2K34JCU.mjs +0 -1496
  248. package/dist/chunk-OFDBEIEK.mjs +0 -16166
  249. package/dist/chunk-SF7YSLF5.mjs +0 -1515
  250. package/dist/chunk-SN4ZDTVW.mjs +0 -16166
  251. package/dist/chunk-WWUSGOXE.mjs +0 -17129
  252. package/dist/constants-VOI7BSLK.mjs +0 -27
  253. package/dist/index-B71aXVzk.d.ts +0 -13264
  254. package/dist/index-BYZbDjal.d.ts +0 -11390
  255. package/dist/index-CHB3KuOB.d.mts +0 -11859
  256. package/dist/index-CzWPI6Le.d.ts +0 -11859
  257. package/dist/index-pOIIuwfV.d.mts +0 -13264
  258. package/dist/index-xbWjohNq.d.mts +0 -11390
  259. package/dist/solana-4O4K45VU.mjs +0 -46
  260. package/dist/solana-5EMCTPTS.mjs +0 -46
  261. package/dist/solana-NDABAZ6P.mjs +0 -56
  262. package/dist/solana-Q4NAVBTS.mjs +0 -46
  263. package/dist/solana-ZYO63LY5.mjs +0 -46
@@ -0,0 +1,816 @@
1
+ /**
2
+ * Solana Noir Verifier
3
+ *
4
+ * Verifies Noir ZK proofs on Solana blockchain.
5
+ *
6
+ * ## Overview
7
+ *
8
+ * This module enables verification of SIP Protocol's Noir proofs on Solana:
9
+ * - Funding Proofs: Prove sufficient balance without revealing amount
10
+ * - Validity Proofs: Prove intent authorization without revealing sender
11
+ * - Fulfillment Proofs: Prove correct execution without revealing path
12
+ *
13
+ * ## Usage
14
+ *
15
+ * ```typescript
16
+ * import { SolanaNoirVerifier } from '@sip-protocol/sdk'
17
+ * import { NoirProofProvider } from '@sip-protocol/sdk'
18
+ *
19
+ * // Generate proof
20
+ * const provider = new NoirProofProvider()
21
+ * await provider.initialize()
22
+ * const { proof } = await provider.generateFundingProof(params)
23
+ *
24
+ * // Verify on Solana
25
+ * const verifier = new SolanaNoirVerifier({ network: 'devnet' })
26
+ * await verifier.initialize()
27
+ *
28
+ * // Off-chain verification (fast, no transaction)
29
+ * const isValid = await verifier.verifyOffChain(proof)
30
+ *
31
+ * // On-chain verification (submits transaction)
32
+ * const result = await verifier.verifyOnChain(proof, wallet)
33
+ * ```
34
+ *
35
+ * ## Architecture
36
+ *
37
+ * ```
38
+ * ┌─────────────────────────────────────────────────────────────┐
39
+ * │ CLIENT SIDE │
40
+ * │ ┌─────────────┐ ┌──────────────────┐ │
41
+ * │ │ Noir Proof │───►│ SolanaNoirVerifier│ │
42
+ * │ │ Provider │ │ - serialize() │ │
43
+ * │ └─────────────┘ │ - verifyOffChain()│ │
44
+ * │ │ - verifyOnChain() │ │
45
+ * │ └────────┬─────────┘ │
46
+ * └──────────────────────────────┼─────────────────────────────┘
47
+ * │
48
+ * ▼
49
+ * ┌─────────────────────────────────────────────────────────────┐
50
+ * │ SOLANA BLOCKCHAIN │
51
+ * │ ┌──────────────────────────────────────────────────────┐ │
52
+ * │ │ ZK Proof Verification Program │ │
53
+ * │ │ - Deserialize proof │ │
54
+ * │ │ - Load verification key │ │
55
+ * │ │ - Execute pairing checks │ │
56
+ * │ │ - Return verification result │ │
57
+ * │ └──────────────────────────────────────────────────────┘ │
58
+ * └─────────────────────────────────────────────────────────────┘
59
+ * ```
60
+ *
61
+ * @module solana/noir-verifier
62
+ */
63
+
64
+ import type { ZKProof } from '@sip-protocol/types'
65
+ import {
66
+ Connection,
67
+ PublicKey,
68
+ Transaction,
69
+ TransactionInstruction,
70
+ ComputeBudgetProgram,
71
+ } from '@solana/web3.js'
72
+ import {
73
+ type NoirCircuitType,
74
+ type SolanaNoirVerifierConfig,
75
+ type SolanaVerificationKey,
76
+ type SolanaSerializedProof,
77
+ type SolanaVerificationResult,
78
+ type SolanaVerifyInstruction,
79
+ type ProofStatistics,
80
+ type BatchVerificationRequest,
81
+ type BatchVerificationResult,
82
+ CIRCUIT_METADATA,
83
+ DEFAULT_RPC_URLS,
84
+ SOLANA_ZK_PROGRAM_IDS,
85
+ SolanaNoirError,
86
+ SolanaNoirErrorCode,
87
+ isNoirCircuitType,
88
+ isValidSolanaProof,
89
+ estimateComputeUnits,
90
+ getSunspotVerifierProgramId,
91
+ } from './noir-verifier-types'
92
+
93
+ // Re-export types for convenience
94
+ export * from './noir-verifier-types'
95
+
96
+ /**
97
+ * Solana Noir Verifier
98
+ *
99
+ * Enables verification of Noir ZK proofs on Solana blockchain.
100
+ *
101
+ * @example
102
+ * ```typescript
103
+ * const verifier = new SolanaNoirVerifier({
104
+ * network: 'devnet',
105
+ * verbose: true,
106
+ * })
107
+ *
108
+ * await verifier.initialize()
109
+ *
110
+ * // Verify proof off-chain (no transaction)
111
+ * const valid = await verifier.verifyOffChain(proof)
112
+ *
113
+ * // Or verify on-chain (submits transaction)
114
+ * const result = await verifier.verifyOnChain(proof, wallet)
115
+ * ```
116
+ */
117
+ export class SolanaNoirVerifier {
118
+ private config: Required<SolanaNoirVerifierConfig>
119
+ private _isReady = false
120
+ private verificationKeys: Map<NoirCircuitType, SolanaVerificationKey> = new Map()
121
+ private connection: Connection
122
+
123
+ constructor(config: SolanaNoirVerifierConfig = {}) {
124
+ const network = config.network ?? 'devnet'
125
+
126
+ this.config = {
127
+ network,
128
+ rpcUrl: config.rpcUrl ?? DEFAULT_RPC_URLS[network],
129
+ programId: config.programId ?? SOLANA_ZK_PROGRAM_IDS.SIP_NOIR_VERIFIER,
130
+ verbose: config.verbose ?? false,
131
+ commitment: config.commitment ?? 'confirmed',
132
+ maxComputeUnits: config.maxComputeUnits ?? 400000,
133
+ }
134
+
135
+ this.connection = new Connection(this.config.rpcUrl, this.config.commitment)
136
+ }
137
+
138
+ /**
139
+ * Get the Solana connection
140
+ */
141
+ getConnection(): Connection {
142
+ return this.connection
143
+ }
144
+
145
+ /**
146
+ * Check if verifier is initialized
147
+ */
148
+ get isReady(): boolean {
149
+ return this._isReady
150
+ }
151
+
152
+ /**
153
+ * Get current configuration
154
+ */
155
+ getConfig(): Readonly<SolanaNoirVerifierConfig> {
156
+ return { ...this.config }
157
+ }
158
+
159
+ /**
160
+ * Get RPC URL being used
161
+ */
162
+ getRpcUrl(): string {
163
+ return this.config.rpcUrl
164
+ }
165
+
166
+ /**
167
+ * Initialize the verifier
168
+ *
169
+ * Loads verification keys for all circuit types.
170
+ */
171
+ async initialize(): Promise<void> {
172
+ if (this._isReady) {
173
+ return
174
+ }
175
+
176
+ if (this.config.verbose) {
177
+ console.log('[SolanaNoirVerifier] Initializing...')
178
+ console.log(`[SolanaNoirVerifier] Network: ${this.config.network}`)
179
+ console.log(`[SolanaNoirVerifier] RPC: ${this.config.rpcUrl}`)
180
+ }
181
+
182
+ try {
183
+ // Generate verification keys for each circuit type
184
+ for (const circuitType of ['funding', 'validity', 'fulfillment'] as NoirCircuitType[]) {
185
+ const vkey = await this.generateVerificationKey(circuitType)
186
+ this.verificationKeys.set(circuitType, vkey)
187
+
188
+ if (this.config.verbose) {
189
+ console.log(`[SolanaNoirVerifier] Loaded ${circuitType} verification key`)
190
+ }
191
+ }
192
+
193
+ this._isReady = true
194
+
195
+ if (this.config.verbose) {
196
+ console.log('[SolanaNoirVerifier] Initialization complete')
197
+ }
198
+ } catch (error) {
199
+ throw new SolanaNoirError(
200
+ `Failed to initialize verifier: ${error instanceof Error ? error.message : String(error)}`,
201
+ SolanaNoirErrorCode.NETWORK_ERROR,
202
+ { error }
203
+ )
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Generate verification key for a circuit type
209
+ *
210
+ * Creates the cryptographic verification key needed to verify proofs.
211
+ */
212
+ async generateVerificationKey(circuitType: NoirCircuitType): Promise<SolanaVerificationKey> {
213
+ if (!isNoirCircuitType(circuitType)) {
214
+ throw new SolanaNoirError(
215
+ `Unsupported circuit type: ${circuitType}`,
216
+ SolanaNoirErrorCode.UNSUPPORTED_CIRCUIT
217
+ )
218
+ }
219
+
220
+ const metadata = CIRCUIT_METADATA[circuitType]
221
+
222
+ // In production, this would load the actual verification key from
223
+ // the compiled circuit artifacts. For now, we generate a deterministic
224
+ // placeholder that matches the circuit structure.
225
+ const keyBytes = this.generateVKeyBytes(circuitType)
226
+ const keyHash = await this.hashBytes(keyBytes)
227
+
228
+ return {
229
+ circuitType,
230
+ keyBytes,
231
+ keyHash,
232
+ publicInputCount: metadata.publicInputCount,
233
+ }
234
+ }
235
+
236
+ /**
237
+ * Serialize a proof for Solana
238
+ *
239
+ * Converts a Noir proof into a format suitable for Solana transaction.
240
+ */
241
+ serializeProof(proof: ZKProof): SolanaSerializedProof {
242
+ if (!isValidSolanaProof(proof)) {
243
+ throw new SolanaNoirError(
244
+ 'Invalid proof structure',
245
+ SolanaNoirErrorCode.INVALID_PROOF_FORMAT,
246
+ { proof }
247
+ )
248
+ }
249
+
250
+ const circuitType = proof.type as NoirCircuitType
251
+
252
+ // Convert hex proof to bytes
253
+ const proofHex = proof.proof.startsWith('0x') ? proof.proof.slice(2) : proof.proof
254
+ const proofBytes = this.hexToBytes(proofHex)
255
+
256
+ // Convert public inputs to bytes
257
+ const publicInputs = proof.publicInputs.map((input) => {
258
+ const inputHex = input.startsWith('0x') ? input.slice(2) : input
259
+ return this.hexToBytes(inputHex.padStart(64, '0'))
260
+ })
261
+
262
+ const totalSize = proofBytes.length + publicInputs.reduce((sum, pi) => sum + pi.length, 0)
263
+
264
+ return {
265
+ circuitType,
266
+ proofBytes,
267
+ publicInputs,
268
+ totalSize,
269
+ }
270
+ }
271
+
272
+ /**
273
+ * Verify a proof off-chain
274
+ *
275
+ * Fast verification without submitting a transaction.
276
+ * Uses the local Noir backend for verification if @aztec/bb.js is available,
277
+ * otherwise falls back to mock verification.
278
+ *
279
+ * @param proof - The proof to verify
280
+ * @returns true if valid, false otherwise
281
+ *
282
+ * @remarks
283
+ * For production use, install @aztec/bb.js as a dependency:
284
+ * ```bash
285
+ * npm install @aztec/bb.js
286
+ * ```
287
+ */
288
+ async verifyOffChain(proof: ZKProof): Promise<boolean> {
289
+ this.ensureReady()
290
+
291
+ if (!isValidSolanaProof(proof)) {
292
+ return false
293
+ }
294
+
295
+ const circuitType = proof.type as NoirCircuitType
296
+ const vkey = this.verificationKeys.get(circuitType)
297
+
298
+ if (!vkey) {
299
+ throw new SolanaNoirError(
300
+ `Verification key not found for circuit: ${circuitType}`,
301
+ SolanaNoirErrorCode.VKEY_NOT_FOUND
302
+ )
303
+ }
304
+
305
+ try {
306
+ // Try to import the Noir backend for real verification
307
+ const bbjs = await this.tryImportBBJS()
308
+
309
+ if (bbjs) {
310
+ return await this.verifyWithBackend(bbjs, proof, circuitType)
311
+ }
312
+
313
+ // Fallback to mock verification if @aztec/bb.js not available
314
+ if (this.config.verbose) {
315
+ console.log('[SolanaNoirVerifier] @aztec/bb.js not available, using mock verification')
316
+ }
317
+ return this.mockVerify(proof)
318
+ } catch (error) {
319
+ if (this.config.verbose) {
320
+ console.error('[SolanaNoirVerifier] Off-chain verification error:', error)
321
+ }
322
+ return false
323
+ }
324
+ }
325
+
326
+ /**
327
+ * Try to import @aztec/bb.js dynamically
328
+ * Returns null if not available (allows graceful fallback)
329
+ */
330
+ private async tryImportBBJS(): Promise<{ UltraHonkBackend: unknown } | null> {
331
+ try {
332
+ // Dynamic import - will fail if package not installed
333
+ const bbjs = await import('@aztec/bb.js')
334
+ return bbjs
335
+ } catch {
336
+ // Package not installed - this is expected in many environments
337
+ return null
338
+ }
339
+ }
340
+
341
+ /**
342
+ * Verify proof using the real Noir backend
343
+ */
344
+ private async verifyWithBackend(
345
+ bbjs: { UltraHonkBackend: unknown },
346
+ proof: ZKProof,
347
+ circuitType: NoirCircuitType
348
+ ): Promise<boolean> {
349
+ // Load the appropriate circuit artifact
350
+ const circuit = await this.loadCircuitArtifact(circuitType)
351
+
352
+ // Create backend and verify
353
+ // Cast required: bbjs is dynamically imported with unknown types
354
+ const Backend = bbjs.UltraHonkBackend as new (bytecode: string) => {
355
+ verifyProof(args: { proof: Uint8Array; publicInputs: string[] }): Promise<boolean>
356
+ destroy(): Promise<void>
357
+ }
358
+ const backend = new Backend(circuit.bytecode)
359
+
360
+ try {
361
+ // Convert proof to bytes
362
+ const proofHex = proof.proof.startsWith('0x') ? proof.proof.slice(2) : proof.proof
363
+ const proofBytes = this.hexToBytes(proofHex)
364
+
365
+ // Strip 0x prefix from public inputs
366
+ const publicInputs = proof.publicInputs.map((input) =>
367
+ input.startsWith('0x') ? input.slice(2) : input
368
+ )
369
+
370
+ const isValid = await backend.verifyProof({
371
+ proof: proofBytes,
372
+ publicInputs,
373
+ })
374
+
375
+ if (this.config.verbose) {
376
+ console.log(`[SolanaNoirVerifier] Off-chain verification: ${isValid ? 'VALID' : 'INVALID'}`)
377
+ }
378
+
379
+ return isValid
380
+ } finally {
381
+ await backend.destroy()
382
+ }
383
+ }
384
+
385
+ /**
386
+ * Mock verification for testing and development
387
+ *
388
+ * WARNING: This does NOT provide cryptographic security.
389
+ * Only used when @aztec/bb.js is not available.
390
+ */
391
+ private mockVerify(proof: ZKProof): boolean {
392
+ // Basic structural validation only
393
+ const proofHex = proof.proof.startsWith('0x') ? proof.proof.slice(2) : proof.proof
394
+
395
+ // Check proof has reasonable size (real proofs are ~2KB)
396
+ if (proofHex.length < 128) {
397
+ return false
398
+ }
399
+
400
+ // Check public inputs exist
401
+ if (proof.publicInputs.length === 0) {
402
+ return false
403
+ }
404
+
405
+ if (this.config.verbose) {
406
+ console.log('[SolanaNoirVerifier] Mock verification: VALID (not cryptographically verified)')
407
+ }
408
+
409
+ return true
410
+ }
411
+
412
+ /**
413
+ * Verify a proof on-chain
414
+ *
415
+ * Submits a transaction to Solana to verify the proof using the Sunspot verifier.
416
+ *
417
+ * @param proof - The proof to verify
418
+ * @param wallet - Wallet interface with signTransaction method
419
+ * @returns Verification result with transaction signature
420
+ */
421
+ async verifyOnChain(
422
+ proof: ZKProof,
423
+ wallet: {
424
+ publicKey: { toBase58(): string }
425
+ signTransaction: <T extends Transaction>(tx: T) => Promise<T>
426
+ }
427
+ ): Promise<SolanaVerificationResult> {
428
+ this.ensureReady()
429
+
430
+ if (!isValidSolanaProof(proof)) {
431
+ return {
432
+ valid: false,
433
+ error: 'Invalid proof structure',
434
+ }
435
+ }
436
+
437
+ const circuitType = proof.type as NoirCircuitType
438
+
439
+ // Get the Sunspot verifier program ID for this circuit type
440
+ const verifierProgramId = getSunspotVerifierProgramId(circuitType, this.config.network)
441
+ if (!verifierProgramId) {
442
+ return {
443
+ valid: false,
444
+ error: `No Sunspot verifier deployed for circuit type: ${circuitType} on ${this.config.network}`,
445
+ }
446
+ }
447
+
448
+ try {
449
+ // First verify off-chain (fast fail for invalid proofs)
450
+ const offChainValid = await this.verifyOffChain(proof)
451
+ if (!offChainValid) {
452
+ return {
453
+ valid: false,
454
+ error: 'Proof failed off-chain verification',
455
+ }
456
+ }
457
+
458
+ // Create Sunspot verify instruction
459
+ const instruction = this.createSunspotVerifyInstruction(proof, verifierProgramId)
460
+
461
+ // Estimate compute units
462
+ const computeUnits = estimateComputeUnits(circuitType)
463
+
464
+ if (computeUnits > this.config.maxComputeUnits) {
465
+ return {
466
+ valid: false,
467
+ error: `Proof requires ${computeUnits} CU, max is ${this.config.maxComputeUnits}`,
468
+ }
469
+ }
470
+
471
+ // Create transaction with compute budget
472
+ const transaction = new Transaction()
473
+
474
+ // Add compute budget instruction
475
+ transaction.add(
476
+ ComputeBudgetProgram.setComputeUnitLimit({ units: this.config.maxComputeUnits })
477
+ )
478
+
479
+ // Add verify instruction
480
+ transaction.add(instruction)
481
+
482
+ // Get recent blockhash
483
+ const { blockhash, lastValidBlockHeight } = await this.connection.getLatestBlockhash(
484
+ this.config.commitment
485
+ )
486
+ transaction.recentBlockhash = blockhash
487
+ transaction.feePayer = new PublicKey(wallet.publicKey.toBase58())
488
+
489
+ // Sign transaction
490
+ const signedTransaction = await wallet.signTransaction(transaction)
491
+
492
+ // Send transaction
493
+ const signature = await this.connection.sendRawTransaction(signedTransaction.serialize())
494
+
495
+ // Wait for confirmation
496
+ const confirmation = await this.connection.confirmTransaction(
497
+ {
498
+ signature,
499
+ blockhash,
500
+ lastValidBlockHeight,
501
+ },
502
+ this.config.commitment
503
+ )
504
+
505
+ if (confirmation.value.err) {
506
+ return {
507
+ valid: false,
508
+ error: `Transaction failed: ${JSON.stringify(confirmation.value.err)}`,
509
+ signature,
510
+ }
511
+ }
512
+
513
+ if (this.config.verbose) {
514
+ console.log(`[SolanaNoirVerifier] On-chain verification: VALID`)
515
+ console.log(`[SolanaNoirVerifier] Signature: ${signature}`)
516
+ console.log(`[SolanaNoirVerifier] Compute units: ${computeUnits}`)
517
+ }
518
+
519
+ return {
520
+ valid: true,
521
+ signature,
522
+ computeUnits,
523
+ }
524
+ } catch (error) {
525
+ return {
526
+ valid: false,
527
+ error: error instanceof Error ? error.message : String(error),
528
+ }
529
+ }
530
+ }
531
+
532
+ /**
533
+ * Create a Sunspot verifier instruction
534
+ *
535
+ * Sunspot verifiers expect instruction data in format: proof_bytes || public_witness_bytes
536
+ */
537
+ createSunspotVerifyInstruction(proof: ZKProof, programId: string): TransactionInstruction {
538
+ const serialized = this.serializeProofForSunspot(proof)
539
+
540
+ return new TransactionInstruction({
541
+ programId: new PublicKey(programId),
542
+ keys: [], // Sunspot verifiers don't require any accounts
543
+ data: serialized,
544
+ })
545
+ }
546
+
547
+ /**
548
+ * Serialize proof for Sunspot verifier
549
+ *
550
+ * Sunspot expects: proof_bytes || public_witness_bytes
551
+ * where public_witness contains the number of public inputs followed by the values
552
+ */
553
+ serializeProofForSunspot(proof: ZKProof): Buffer {
554
+ // Convert hex proof to bytes
555
+ const proofHex = proof.proof.startsWith('0x') ? proof.proof.slice(2) : proof.proof
556
+ const proofBytes = Buffer.from(proofHex, 'hex')
557
+
558
+ // Convert public inputs to public witness format
559
+ // Format: [num_inputs (4 bytes LE)] [input_1 (32 bytes)] [input_2 (32 bytes)] ...
560
+ const numInputs = proof.publicInputs.length
561
+ const publicWitnessSize = 4 + numInputs * 32
562
+
563
+ const publicWitness = Buffer.alloc(publicWitnessSize)
564
+ publicWitness.writeUInt32LE(numInputs, 0)
565
+
566
+ for (let i = 0; i < numInputs; i++) {
567
+ const inputHex = proof.publicInputs[i].startsWith('0x')
568
+ ? proof.publicInputs[i].slice(2)
569
+ : proof.publicInputs[i]
570
+ const inputBytes = Buffer.from(inputHex.padStart(64, '0'), 'hex')
571
+ inputBytes.copy(publicWitness, 4 + i * 32)
572
+ }
573
+
574
+ // Concatenate proof and public witness
575
+ return Buffer.concat([proofBytes, publicWitness])
576
+ }
577
+
578
+ /**
579
+ * Create a verify instruction for Solana
580
+ *
581
+ * Builds the instruction data and account metas needed for verification.
582
+ */
583
+ createVerifyInstruction(proof: ZKProof): SolanaVerifyInstruction {
584
+ const serialized = this.serializeProof(proof)
585
+ const circuitType = proof.type as NoirCircuitType
586
+
587
+ // Build instruction data
588
+ // Format: [discriminator (1 byte)] [circuit_type (1 byte)] [proof_len (4 bytes)] [proof] [inputs]
589
+ const discriminator = 0x01 // Verify instruction
590
+ const circuitTypeId = this.circuitTypeToId(circuitType)
591
+
592
+ const proofLen = serialized.proofBytes.length
593
+ const data = new Uint8Array(
594
+ 1 + 1 + 4 + proofLen + serialized.publicInputs.length * 32
595
+ )
596
+
597
+ let offset = 0
598
+ data[offset++] = discriminator
599
+ data[offset++] = circuitTypeId
600
+
601
+ // Write proof length (little-endian u32)
602
+ data[offset++] = proofLen & 0xff
603
+ data[offset++] = (proofLen >> 8) & 0xff
604
+ data[offset++] = (proofLen >> 16) & 0xff
605
+ data[offset++] = (proofLen >> 24) & 0xff
606
+
607
+ // Write proof bytes
608
+ data.set(serialized.proofBytes, offset)
609
+ offset += proofLen
610
+
611
+ // Write public inputs (each 32 bytes)
612
+ for (const input of serialized.publicInputs) {
613
+ data.set(input, offset)
614
+ offset += 32
615
+ }
616
+
617
+ return {
618
+ programId: this.config.programId,
619
+ data,
620
+ keys: [
621
+ {
622
+ pubkey: this.config.programId, // Verification key account (PDA)
623
+ isSigner: false,
624
+ isWritable: false,
625
+ },
626
+ ],
627
+ }
628
+ }
629
+
630
+ /**
631
+ * Get proof statistics
632
+ *
633
+ * Returns size and compute unit estimates for a proof.
634
+ */
635
+ getProofStatistics(proof: ZKProof): ProofStatistics {
636
+ const serialized = this.serializeProof(proof)
637
+ const circuitType = proof.type as NoirCircuitType
638
+
639
+ return {
640
+ circuitType,
641
+ proofSize: serialized.proofBytes.length,
642
+ publicInputsSize: serialized.publicInputs.length * 32,
643
+ totalSize: serialized.totalSize,
644
+ estimatedComputeUnits: estimateComputeUnits(circuitType),
645
+ }
646
+ }
647
+
648
+ /**
649
+ * Batch verify multiple proofs
650
+ *
651
+ * Verifies multiple proofs, optionally failing fast on first invalid.
652
+ */
653
+ async batchVerify(request: BatchVerificationRequest): Promise<BatchVerificationResult> {
654
+ this.ensureReady()
655
+
656
+ const results: SolanaVerificationResult[] = []
657
+ let validCount = 0
658
+ let totalComputeUnits = 0
659
+
660
+ for (const proof of request.proofs) {
661
+ const valid = await this.verifyOffChain(proof)
662
+ const computeUnits = isValidSolanaProof(proof)
663
+ ? estimateComputeUnits(proof.type as NoirCircuitType)
664
+ : 0
665
+
666
+ results.push({
667
+ valid,
668
+ computeUnits,
669
+ })
670
+
671
+ if (valid) {
672
+ validCount++
673
+ }
674
+ totalComputeUnits += computeUnits
675
+
676
+ // Fail fast if requested and we found an invalid proof
677
+ if (request.failFast && !valid) {
678
+ break
679
+ }
680
+ }
681
+
682
+ return {
683
+ success: validCount === request.proofs.length,
684
+ results,
685
+ totalVerified: results.length,
686
+ validCount,
687
+ totalComputeUnits,
688
+ }
689
+ }
690
+
691
+ /**
692
+ * Get verification key for a circuit type
693
+ */
694
+ getVerificationKey(circuitType: NoirCircuitType): SolanaVerificationKey | undefined {
695
+ return this.verificationKeys.get(circuitType)
696
+ }
697
+
698
+ /**
699
+ * Destroy the verifier and free resources
700
+ */
701
+ async destroy(): Promise<void> {
702
+ this.verificationKeys.clear()
703
+ this._isReady = false
704
+ }
705
+
706
+ // ─── Private Methods ───────────────────────────────────────────────────────
707
+
708
+ private ensureReady(): void {
709
+ if (!this._isReady) {
710
+ throw new SolanaNoirError(
711
+ 'Verifier not initialized. Call initialize() first.',
712
+ SolanaNoirErrorCode.NETWORK_ERROR
713
+ )
714
+ }
715
+ }
716
+
717
+ private async loadCircuitArtifact(circuitType: NoirCircuitType): Promise<{ bytecode: string }> {
718
+ try {
719
+ // Dynamically import circuit artifacts
720
+ switch (circuitType) {
721
+ case 'funding':
722
+ return await import('../proofs/circuits/funding_proof.json') as { bytecode: string }
723
+ case 'validity':
724
+ return await import('../proofs/circuits/validity_proof.json') as { bytecode: string }
725
+ case 'fulfillment':
726
+ return await import('../proofs/circuits/fulfillment_proof.json') as { bytecode: string }
727
+ default:
728
+ throw new SolanaNoirError(
729
+ `Unknown circuit type: ${circuitType}`,
730
+ SolanaNoirErrorCode.UNSUPPORTED_CIRCUIT
731
+ )
732
+ }
733
+ } catch (error) {
734
+ // Circuit artifacts may not be compiled yet
735
+ if (error instanceof SolanaNoirError) {
736
+ throw error
737
+ }
738
+ throw new SolanaNoirError(
739
+ `Circuit artifact not found for ${circuitType}. ` +
740
+ `Ensure circuit is compiled: cd circuits && nargo compile`,
741
+ SolanaNoirErrorCode.VKEY_NOT_FOUND,
742
+ { circuitType, originalError: error instanceof Error ? error.message : String(error) }
743
+ )
744
+ }
745
+ }
746
+
747
+ private generateVKeyBytes(circuitType: NoirCircuitType): Uint8Array {
748
+ // Generate deterministic verification key bytes
749
+ // In production, these would come from the compiled circuit
750
+ const metadata = CIRCUIT_METADATA[circuitType]
751
+ const seed = `sip-noir-vkey-${circuitType}-${metadata.versionHash}`
752
+
753
+ // Create deterministic bytes from seed
754
+ const encoder = new TextEncoder()
755
+ const seedBytes = encoder.encode(seed)
756
+
757
+ // Pad to 256 bytes (typical vkey size)
758
+ const vkeyBytes = new Uint8Array(256)
759
+ vkeyBytes.set(seedBytes.slice(0, Math.min(seedBytes.length, 256)))
760
+
761
+ return vkeyBytes
762
+ }
763
+
764
+ private async hashBytes(bytes: Uint8Array): Promise<string> {
765
+ const { sha256 } = await import('@noble/hashes/sha256')
766
+ const { bytesToHex } = await import('@noble/hashes/utils')
767
+ return bytesToHex(sha256(bytes))
768
+ }
769
+
770
+ private hexToBytes(hex: string): Uint8Array {
771
+ const h = hex.startsWith('0x') ? hex.slice(2) : hex
772
+ const bytes = new Uint8Array(h.length / 2)
773
+ for (let i = 0; i < bytes.length; i++) {
774
+ bytes[i] = parseInt(h.slice(i * 2, i * 2 + 2), 16)
775
+ }
776
+ return bytes
777
+ }
778
+
779
+ private circuitTypeToId(circuitType: NoirCircuitType): number {
780
+ switch (circuitType) {
781
+ case 'funding':
782
+ return 0
783
+ case 'validity':
784
+ return 1
785
+ case 'fulfillment':
786
+ return 2
787
+ default:
788
+ return 255
789
+ }
790
+ }
791
+
792
+ }
793
+
794
+ /**
795
+ * Create a Solana Noir Verifier with default devnet configuration
796
+ */
797
+ export function createDevnetVerifier(
798
+ config: Omit<SolanaNoirVerifierConfig, 'network'> = {}
799
+ ): SolanaNoirVerifier {
800
+ return new SolanaNoirVerifier({
801
+ ...config,
802
+ network: 'devnet',
803
+ })
804
+ }
805
+
806
+ /**
807
+ * Create a Solana Noir Verifier with mainnet configuration
808
+ */
809
+ export function createMainnetVerifier(
810
+ config: Omit<SolanaNoirVerifierConfig, 'network'> = {}
811
+ ): SolanaNoirVerifier {
812
+ return new SolanaNoirVerifier({
813
+ ...config,
814
+ network: 'mainnet-beta',
815
+ })
816
+ }