@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,522 @@
1
+ /**
2
+ * Ethereum Pedersen Commitment Implementation
3
+ *
4
+ * Secp256k1-based Pedersen commitments for ERC-20 token privacy on Ethereum.
5
+ *
6
+ * ## Security Properties
7
+ *
8
+ * - **Hiding (Computational)**: Cannot determine value from commitment
9
+ * - **Binding (Computational)**: Cannot open commitment to different value
10
+ * - **Homomorphic**: C(v1) + C(v2) = C(v1 + v2) when blindings sum
11
+ *
12
+ * ## Secp256k1 Curve
13
+ *
14
+ * This implementation uses secp256k1 for compatibility with Ethereum's
15
+ * native cryptography and existing EVM tooling.
16
+ *
17
+ * ## Ethereum Token Amounts
18
+ *
19
+ * Ethereum uses uint256 for token amounts (18 decimals for ETH, varies for ERC-20).
20
+ * Pedersen commitments operate on values < curve order.
21
+ *
22
+ * @module chains/ethereum/commitment
23
+ */
24
+
25
+ import { secp256k1 } from '@noble/curves/secp256k1'
26
+ import { sha256 } from '@noble/hashes/sha256'
27
+ import { bytesToHex, randomBytes } from '@noble/hashes/utils'
28
+ import type { HexString } from '@sip-protocol/types'
29
+ import { ValidationError, CryptoError, ErrorCode } from '../../errors'
30
+ import type { EthereumPedersenCommitment, ERC20TokenCommitment } from './types'
31
+
32
+ // ─── Types ────────────────────────────────────────────────────────────────────
33
+
34
+ /**
35
+ * A commitment point without the blinding factor (for public sharing)
36
+ */
37
+ export interface EthereumCommitmentPoint {
38
+ /** The commitment point (compressed secp256k1, 33 bytes) */
39
+ commitment: HexString
40
+ }
41
+
42
+ // ─── Constants ────────────────────────────────────────────────────────────────
43
+
44
+ /**
45
+ * Domain separation tag for H generation (Ethereum version)
46
+ */
47
+ const H_DOMAIN = 'SIP-ETHEREUM-PEDERSEN-GENERATOR-H-v1'
48
+
49
+ /**
50
+ * The generator G (secp256k1 base point)
51
+ */
52
+ const G = secp256k1.ProjectivePoint.BASE
53
+
54
+ /**
55
+ * The secp256k1 curve order n
56
+ */
57
+ export const SECP256K1_ORDER = secp256k1.CURVE.n
58
+
59
+ /**
60
+ * Maximum ETH amount (theoretical max uint256, but we limit to curve order)
61
+ */
62
+ export const MAX_ETH_AMOUNT = 2n ** 256n - 1n
63
+
64
+ /**
65
+ * Maximum value that can be committed (must be < curve order)
66
+ */
67
+ export const MAX_COMMITMENT_VALUE = SECP256K1_ORDER - 1n
68
+
69
+ // ─── Generator H Construction ─────────────────────────────────────────────────
70
+
71
+ /**
72
+ * The independent generator H (NUMS point)
73
+ * Constructed via hash-to-curve with nothing-up-my-sleeve string.
74
+ */
75
+ const H = generateH()
76
+
77
+ /**
78
+ * Generate the independent generator H using NUMS method for secp256k1
79
+ *
80
+ * Uses a hash-and-check approach:
81
+ * 1. Hash domain||counter to get 32 bytes
82
+ * 2. Try to use as x-coordinate with even y
83
+ * 3. If valid point and not identity/G, use it
84
+ */
85
+ function generateH(): typeof G {
86
+ let counter = 0
87
+
88
+ while (counter < 256) {
89
+ // Create input: domain || counter
90
+ const input = new TextEncoder().encode(`${H_DOMAIN}:${counter}`)
91
+ const hashBytes = sha256(input)
92
+
93
+ try {
94
+ // Try to create a point with the hash as x-coordinate (compressed, even y = 0x02)
95
+ const compressedPoint = new Uint8Array(33)
96
+ compressedPoint[0] = 0x02 // even y prefix
97
+ compressedPoint.set(hashBytes, 1)
98
+
99
+ const point = secp256k1.ProjectivePoint.fromHex(compressedPoint)
100
+
101
+ // Verify it's not identity or G
102
+ if (!point.equals(secp256k1.ProjectivePoint.ZERO)) {
103
+ const gBytes = G.toRawBytes(true)
104
+ const hBytes = point.toRawBytes(true)
105
+ if (bytesToHex(gBytes) !== bytesToHex(hBytes)) {
106
+ return point
107
+ }
108
+ }
109
+ } catch {
110
+ // Not a valid x-coordinate, try next counter
111
+ }
112
+
113
+ counter++
114
+ }
115
+
116
+ // Should never reach here with a proper hash function
117
+ throw new CryptoError(
118
+ 'Failed to generate independent generator H after 256 attempts',
119
+ ErrorCode.CRYPTO_FAILED
120
+ )
121
+ }
122
+
123
+ // ─── Core Commitment Functions ────────────────────────────────────────────────
124
+
125
+ /**
126
+ * Create a Pedersen commitment for an Ethereum amount
127
+ *
128
+ * Commitment: C = v*G + r*H where:
129
+ * - v is the value (amount in wei)
130
+ * - G is the secp256k1 generator
131
+ * - r is a random blinding factor
132
+ * - H is an independent generator (NUMS)
133
+ *
134
+ * @param value - Amount to commit (in wei or token smallest units)
135
+ * @param blinding - Optional blinding factor (32 bytes). Random if not provided.
136
+ * @returns Commitment and blinding factor
137
+ *
138
+ * @example
139
+ * ```typescript
140
+ * // Commit to 1 ETH (in wei)
141
+ * const commitment = commitETH(10n ** 18n)
142
+ * console.log(commitment.commitment) // '0x02...'
143
+ * console.log(commitment.blinding) // '0x...' (keep secret!)
144
+ * ```
145
+ */
146
+ export function commitETH(
147
+ value: bigint,
148
+ blinding?: Uint8Array
149
+ ): EthereumPedersenCommitment {
150
+ // Validate value
151
+ if (value < 0n) {
152
+ throw new ValidationError('value must be non-negative', 'value')
153
+ }
154
+
155
+ if (value > MAX_COMMITMENT_VALUE) {
156
+ throw new ValidationError(
157
+ `value must be less than curve order (${MAX_COMMITMENT_VALUE})`,
158
+ 'value'
159
+ )
160
+ }
161
+
162
+ // Generate or use provided blinding factor
163
+ const blindingBytes = blinding ?? randomBytes(32)
164
+
165
+ // Convert blinding to scalar (mod n)
166
+ const blindingScalar = bytesToBigInt(blindingBytes) % SECP256K1_ORDER
167
+
168
+ // Compute commitment: C = v*G + r*H
169
+ // Special case: if value is 0, commitment is just r*H
170
+ let commitment: typeof G
171
+ if (value === 0n) {
172
+ commitment = H.multiply(blindingScalar)
173
+ } else {
174
+ const vG = G.multiply(value)
175
+ const rH = H.multiply(blindingScalar)
176
+ commitment = vG.add(rH)
177
+ }
178
+
179
+ // Compress the commitment point
180
+ const commitmentBytes = commitment.toRawBytes(true)
181
+
182
+ return {
183
+ commitment: `0x${bytesToHex(commitmentBytes)}` as HexString,
184
+ blinding: `0x${bytesToHex(blindingBytes)}` as HexString,
185
+ }
186
+ }
187
+
188
+ /**
189
+ * Verify a Pedersen commitment opening
190
+ *
191
+ * Checks that C = v*G + r*H for the given value and blinding.
192
+ *
193
+ * @param commitment - The commitment to verify
194
+ * @param value - The claimed value
195
+ * @param blinding - The blinding factor
196
+ * @returns True if the opening is valid
197
+ *
198
+ * @example
199
+ * ```typescript
200
+ * const isValid = verifyOpeningETH(
201
+ * commitment.commitment,
202
+ * originalValue,
203
+ * commitment.blinding
204
+ * )
205
+ * console.log(isValid) // true
206
+ * ```
207
+ */
208
+ export function verifyOpeningETH(
209
+ commitment: HexString,
210
+ value: bigint,
211
+ blinding: HexString
212
+ ): boolean {
213
+ try {
214
+ // Parse commitment point
215
+ const commitmentBytes = hexToBytes(commitment.slice(2))
216
+ const commitmentPoint = secp256k1.ProjectivePoint.fromHex(commitmentBytes)
217
+
218
+ // Parse blinding factor
219
+ const blindingBytes = hexToBytes(blinding.slice(2))
220
+ const blindingScalar = bytesToBigInt(blindingBytes) % SECP256K1_ORDER
221
+
222
+ // Recompute expected commitment
223
+ let expectedCommitment: typeof G
224
+ if (value === 0n) {
225
+ expectedCommitment = H.multiply(blindingScalar)
226
+ } else {
227
+ const vG = G.multiply(value)
228
+ const rH = H.multiply(blindingScalar)
229
+ expectedCommitment = vG.add(rH)
230
+ }
231
+
232
+ // Compare
233
+ return commitmentPoint.equals(expectedCommitment)
234
+ } catch {
235
+ return false
236
+ }
237
+ }
238
+
239
+ // ─── ERC-20 Token Commitments ─────────────────────────────────────────────────
240
+
241
+ /**
242
+ * Create a Pedersen commitment for an ERC-20 token amount
243
+ *
244
+ * @param amount - Amount in token's smallest units
245
+ * @param tokenContract - ERC-20 token contract address
246
+ * @param decimals - Token decimals
247
+ * @param blinding - Optional blinding factor
248
+ * @returns Token commitment with metadata
249
+ *
250
+ * @example
251
+ * ```typescript
252
+ * // Commit to 100 USDC (6 decimals)
253
+ * const commitment = commitERC20Token(
254
+ * 100_000_000n, // 100 USDC in smallest units
255
+ * '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
256
+ * 6
257
+ * )
258
+ * ```
259
+ */
260
+ export function commitERC20Token(
261
+ amount: bigint,
262
+ tokenContract: HexString,
263
+ decimals: number,
264
+ blinding?: Uint8Array
265
+ ): ERC20TokenCommitment {
266
+ const base = commitETH(amount, blinding)
267
+
268
+ return {
269
+ ...base,
270
+ tokenContract,
271
+ decimals,
272
+ amountRaw: amount,
273
+ }
274
+ }
275
+
276
+ /**
277
+ * Verify an ERC-20 token commitment
278
+ *
279
+ * @param tokenCommitment - The token commitment to verify
280
+ * @param expectedAmount - The expected amount
281
+ * @returns True if valid
282
+ */
283
+ export function verifyERC20TokenCommitment(
284
+ tokenCommitment: ERC20TokenCommitment,
285
+ expectedAmount: bigint
286
+ ): boolean {
287
+ return verifyOpeningETH(
288
+ tokenCommitment.commitment,
289
+ expectedAmount,
290
+ tokenCommitment.blinding
291
+ )
292
+ }
293
+
294
+ // ─── Homomorphic Operations ───────────────────────────────────────────────────
295
+
296
+ /**
297
+ * Add two commitments (homomorphic addition)
298
+ *
299
+ * C(v1, r1) + C(v2, r2) = C(v1+v2, r1+r2)
300
+ *
301
+ * @param c1 - First commitment
302
+ * @param c2 - Second commitment
303
+ * @returns Sum commitment point
304
+ *
305
+ * @example
306
+ * ```typescript
307
+ * const c1 = commitETH(100n)
308
+ * const c2 = commitETH(50n)
309
+ * const sum = addCommitmentsETH(c1.commitment, c2.commitment)
310
+ * // sum.commitment == commitment of 150n with r1+r2 blinding
311
+ * ```
312
+ */
313
+ export function addCommitmentsETH(
314
+ c1: HexString,
315
+ c2: HexString
316
+ ): EthereumCommitmentPoint {
317
+ const point1 = secp256k1.ProjectivePoint.fromHex(hexToBytes(c1.slice(2)))
318
+ const point2 = secp256k1.ProjectivePoint.fromHex(hexToBytes(c2.slice(2)))
319
+
320
+ const sum = point1.add(point2)
321
+ const sumBytes = sum.toRawBytes(true)
322
+
323
+ return {
324
+ commitment: `0x${bytesToHex(sumBytes)}` as HexString,
325
+ }
326
+ }
327
+
328
+ /**
329
+ * Subtract two commitments (homomorphic subtraction)
330
+ *
331
+ * C(v1, r1) - C(v2, r2) = C(v1-v2, r1-r2)
332
+ *
333
+ * @param c1 - First commitment
334
+ * @param c2 - Second commitment
335
+ * @returns Difference commitment point
336
+ */
337
+ export function subtractCommitmentsETH(
338
+ c1: HexString,
339
+ c2: HexString
340
+ ): EthereumCommitmentPoint {
341
+ const point1 = secp256k1.ProjectivePoint.fromHex(hexToBytes(c1.slice(2)))
342
+ const point2 = secp256k1.ProjectivePoint.fromHex(hexToBytes(c2.slice(2)))
343
+
344
+ const diff = point1.subtract(point2)
345
+ const diffBytes = diff.toRawBytes(true)
346
+
347
+ return {
348
+ commitment: `0x${bytesToHex(diffBytes)}` as HexString,
349
+ }
350
+ }
351
+
352
+ /**
353
+ * Add two blinding factors (mod curve order)
354
+ *
355
+ * @param b1 - First blinding factor
356
+ * @param b2 - Second blinding factor
357
+ * @returns Sum of blindings
358
+ */
359
+ export function addBlindingsETH(b1: HexString, b2: HexString): HexString {
360
+ const scalar1 = bytesToBigInt(hexToBytes(b1.slice(2)))
361
+ const scalar2 = bytesToBigInt(hexToBytes(b2.slice(2)))
362
+
363
+ const sum = (scalar1 + scalar2) % SECP256K1_ORDER
364
+ const sumBytes = bigIntToBytes(sum, 32)
365
+
366
+ return `0x${bytesToHex(sumBytes)}` as HexString
367
+ }
368
+
369
+ /**
370
+ * Subtract two blinding factors (mod curve order)
371
+ *
372
+ * @param b1 - First blinding factor
373
+ * @param b2 - Second blinding factor
374
+ * @returns Difference of blindings
375
+ */
376
+ export function subtractBlindingsETH(b1: HexString, b2: HexString): HexString {
377
+ const scalar1 = bytesToBigInt(hexToBytes(b1.slice(2)))
378
+ const scalar2 = bytesToBigInt(hexToBytes(b2.slice(2)))
379
+
380
+ // Handle underflow with modular arithmetic
381
+ const diff = (scalar1 - scalar2 + SECP256K1_ORDER) % SECP256K1_ORDER
382
+ const diffBytes = bigIntToBytes(diff, 32)
383
+
384
+ return `0x${bytesToHex(diffBytes)}` as HexString
385
+ }
386
+
387
+ // ─── Utility Functions ────────────────────────────────────────────────────────
388
+
389
+ /**
390
+ * Get the generators G and H
391
+ *
392
+ * @returns Object with G and H as hex strings
393
+ */
394
+ export function getGeneratorsETH(): { G: HexString; H: HexString } {
395
+ return {
396
+ G: `0x${bytesToHex(G.toRawBytes(true))}` as HexString,
397
+ H: `0x${bytesToHex(H.toRawBytes(true))}` as HexString,
398
+ }
399
+ }
400
+
401
+ /**
402
+ * Generate a random blinding factor
403
+ *
404
+ * @returns Random 32-byte blinding factor
405
+ */
406
+ export function generateBlindingETH(): HexString {
407
+ const blinding = randomBytes(32)
408
+ return `0x${bytesToHex(blinding)}` as HexString
409
+ }
410
+
411
+ /**
412
+ * Convert ETH amount to wei
413
+ *
414
+ * @param amount - Amount in ETH (as number or string)
415
+ * @param decimals - Decimals (default 18 for ETH)
416
+ * @returns Amount in wei
417
+ *
418
+ * @example
419
+ * ```typescript
420
+ * const wei = toWei(1.5) // 1.5 ETH
421
+ * console.log(wei) // 1500000000000000000n
422
+ * ```
423
+ */
424
+ export function toWei(amount: number | string, decimals: number = 18): bigint {
425
+ const str = typeof amount === 'number' ? amount.toString() : amount
426
+ const [whole, fraction = ''] = str.split('.')
427
+
428
+ // Pad or truncate fraction to match decimals
429
+ const paddedFraction = fraction.padEnd(decimals, '0').slice(0, decimals)
430
+ const combined = `${whole}${paddedFraction}`
431
+
432
+ return BigInt(combined)
433
+ }
434
+
435
+ /**
436
+ * Convert wei to ETH
437
+ *
438
+ * @param wei - Amount in wei
439
+ * @param decimals - Decimals (default 18 for ETH)
440
+ * @returns Amount in ETH as string
441
+ *
442
+ * @example
443
+ * ```typescript
444
+ * const eth = fromWei(1500000000000000000n)
445
+ * console.log(eth) // '1.5'
446
+ * ```
447
+ */
448
+ export function fromWei(wei: bigint, decimals: number = 18): string {
449
+ const divisor = 10n ** BigInt(decimals)
450
+ const whole = wei / divisor
451
+ const fraction = wei % divisor
452
+
453
+ if (fraction === 0n) {
454
+ return whole.toString()
455
+ }
456
+
457
+ const fractionStr = fraction.toString().padStart(decimals, '0')
458
+ // Remove trailing zeros
459
+ const trimmed = fractionStr.replace(/0+$/, '')
460
+
461
+ return `${whole}.${trimmed}`
462
+ }
463
+
464
+ /**
465
+ * Create a zero commitment (for proving zero balance)
466
+ *
467
+ * @returns Commitment to zero value
468
+ */
469
+ export function createZeroCommitmentETH(): EthereumPedersenCommitment {
470
+ return commitETH(0n)
471
+ }
472
+
473
+ /**
474
+ * Check if a commitment is to zero (given the blinding)
475
+ *
476
+ * @param commitment - The commitment
477
+ * @param blinding - The blinding factor
478
+ * @returns True if commitment is to zero
479
+ */
480
+ export function isZeroCommitmentETH(
481
+ commitment: HexString,
482
+ blinding: HexString
483
+ ): boolean {
484
+ return verifyOpeningETH(commitment, 0n, blinding)
485
+ }
486
+
487
+ // ─── Helper Functions ─────────────────────────────────────────────────────────
488
+
489
+ /**
490
+ * Convert bytes to bigint (big-endian)
491
+ */
492
+ function bytesToBigInt(bytes: Uint8Array): bigint {
493
+ let result = 0n
494
+ for (let i = 0; i < bytes.length; i++) {
495
+ result = (result << 8n) + BigInt(bytes[i])
496
+ }
497
+ return result
498
+ }
499
+
500
+ /**
501
+ * Convert bigint to bytes (big-endian)
502
+ */
503
+ function bigIntToBytes(num: bigint, length: number): Uint8Array {
504
+ const bytes = new Uint8Array(length)
505
+ let n = num
506
+ for (let i = length - 1; i >= 0; i--) {
507
+ bytes[i] = Number(n & 0xffn)
508
+ n >>= 8n
509
+ }
510
+ return bytes
511
+ }
512
+
513
+ /**
514
+ * Convert hex string to bytes
515
+ */
516
+ function hexToBytes(hex: string): Uint8Array {
517
+ const bytes = new Uint8Array(hex.length / 2)
518
+ for (let i = 0; i < bytes.length; i++) {
519
+ bytes[i] = parseInt(hex.substr(i * 2, 2), 16)
520
+ }
521
+ return bytes
522
+ }