@sip-protocol/sdk 0.7.3 → 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 (264) 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 +47556 -19603
  7. package/dist/browser.mjs +628 -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-3M3HNQCW.mjs → chunk-YWGJ77A2.mjs} +28656 -13103
  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-DIBZHOOQ.d.ts → index-DXh2IGkz.d.ts} +21239 -10304
  24. package/dist/{index-8MQz13eJ.d.mts → index-DeE1ZzA4.d.mts} +21239 -10304
  25. package/dist/index.d.mts +9 -3
  26. package/dist/index.d.ts +9 -3
  27. package/dist/index.js +48396 -19623
  28. package/dist/index.mjs +537 -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 +252 -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 +47 -6
  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 +186 -33
  98. package/src/chains/solana/providers/index.ts +31 -0
  99. package/src/chains/solana/providers/interface.ts +61 -18
  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 +338 -67
  103. package/src/chains/solana/rpc-client.ts +1150 -0
  104. package/src/chains/solana/scan.ts +83 -66
  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 +57 -6
  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 +23 -0
  116. package/src/compliance/range-sas.ts +398 -33
  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 +686 -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 +254 -4
  143. package/src/privacy-backends/interface.ts +649 -6
  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.ts +13 -17
  148. package/src/privacy-backends/private-swap.ts +570 -0
  149. package/src/privacy-backends/rate-limiter.ts +683 -0
  150. package/src/privacy-backends/registry.ts +414 -2
  151. package/src/privacy-backends/router.ts +283 -3
  152. package/src/privacy-backends/shadowwire.ts +449 -0
  153. package/src/privacy-backends/sip-native.ts +3 -0
  154. package/src/privacy-logger.ts +191 -0
  155. package/src/production-safety.ts +373 -0
  156. package/src/proofs/aggregator.ts +1029 -0
  157. package/src/proofs/browser-composer.ts +1150 -0
  158. package/src/proofs/browser.ts +113 -25
  159. package/src/proofs/cache/index.ts +127 -0
  160. package/src/proofs/cache/interface.ts +545 -0
  161. package/src/proofs/cache/key-generator.ts +188 -0
  162. package/src/proofs/cache/lru-cache.ts +481 -0
  163. package/src/proofs/cache/multi-tier-cache.ts +575 -0
  164. package/src/proofs/cache/persistent-cache.ts +788 -0
  165. package/src/proofs/compliance-proof.ts +872 -0
  166. package/src/proofs/composer/base.ts +923 -0
  167. package/src/proofs/composer/index.ts +25 -0
  168. package/src/proofs/composer/interface.ts +518 -0
  169. package/src/proofs/composer/types.ts +383 -0
  170. package/src/proofs/converters/halo2.ts +452 -0
  171. package/src/proofs/converters/index.ts +208 -0
  172. package/src/proofs/converters/interface.ts +363 -0
  173. package/src/proofs/converters/kimchi.ts +462 -0
  174. package/src/proofs/converters/noir.ts +451 -0
  175. package/src/proofs/fallback.ts +888 -0
  176. package/src/proofs/halo2.ts +42 -0
  177. package/src/proofs/index.ts +471 -0
  178. package/src/proofs/interface.ts +13 -0
  179. package/src/proofs/kimchi.ts +42 -0
  180. package/src/proofs/lazy.ts +1004 -0
  181. package/src/proofs/mock.ts +25 -1
  182. package/src/proofs/noir.ts +110 -29
  183. package/src/proofs/orchestrator.ts +960 -0
  184. package/src/proofs/parallel/concurrency.ts +297 -0
  185. package/src/proofs/parallel/dependency-graph.ts +602 -0
  186. package/src/proofs/parallel/executor.ts +420 -0
  187. package/src/proofs/parallel/index.ts +131 -0
  188. package/src/proofs/parallel/interface.ts +685 -0
  189. package/src/proofs/parallel/worker-pool.ts +644 -0
  190. package/src/proofs/providers/halo2.ts +560 -0
  191. package/src/proofs/providers/index.ts +34 -0
  192. package/src/proofs/providers/kimchi.ts +641 -0
  193. package/src/proofs/validator.ts +881 -0
  194. package/src/proofs/verifier.ts +867 -0
  195. package/src/quantum/index.ts +112 -0
  196. package/src/quantum/winternitz-vault.ts +639 -0
  197. package/src/quantum/wots.ts +611 -0
  198. package/src/settlement/backends/direct-chain.ts +1 -0
  199. package/src/settlement/index.ts +9 -0
  200. package/src/settlement/router.ts +732 -46
  201. package/src/solana/index.ts +72 -0
  202. package/src/solana/jito-relayer.ts +687 -0
  203. package/src/solana/noir-verifier-types.ts +430 -0
  204. package/src/solana/noir-verifier.ts +816 -0
  205. package/src/stealth/address-derivation.ts +193 -0
  206. package/src/stealth/ed25519.ts +431 -0
  207. package/src/stealth/index.ts +233 -0
  208. package/src/stealth/meta-address.ts +221 -0
  209. package/src/stealth/secp256k1.ts +368 -0
  210. package/src/stealth/utils.ts +194 -0
  211. package/src/stealth.ts +50 -1504
  212. package/src/sync/index.ts +106 -0
  213. package/src/sync/manager.ts +504 -0
  214. package/src/sync/mock-provider.ts +318 -0
  215. package/src/sync/oblivious.ts +625 -0
  216. package/src/tokens/index.ts +15 -0
  217. package/src/tokens/registry.ts +301 -0
  218. package/src/utils/deprecation.ts +94 -0
  219. package/src/utils/index.ts +9 -0
  220. package/src/wallet/ethereum/index.ts +68 -0
  221. package/src/wallet/ethereum/metamask-privacy.ts +420 -0
  222. package/src/wallet/ethereum/multi-wallet.ts +646 -0
  223. package/src/wallet/ethereum/privacy-adapter.ts +700 -0
  224. package/src/wallet/ethereum/types.ts +3 -1
  225. package/src/wallet/ethereum/walletconnect-adapter.ts +675 -0
  226. package/src/wallet/hardware/index.ts +10 -0
  227. package/src/wallet/hardware/ledger-privacy.ts +414 -0
  228. package/src/wallet/index.ts +71 -0
  229. package/src/wallet/near/adapter.ts +626 -0
  230. package/src/wallet/near/index.ts +86 -0
  231. package/src/wallet/near/meteor-wallet.ts +1153 -0
  232. package/src/wallet/near/my-near-wallet.ts +790 -0
  233. package/src/wallet/near/wallet-selector.ts +702 -0
  234. package/src/wallet/solana/adapter.ts +6 -4
  235. package/src/wallet/solana/index.ts +13 -0
  236. package/src/wallet/solana/privacy-adapter.ts +567 -0
  237. package/src/wallet/sui/types.ts +6 -4
  238. package/src/zcash/rpc-client.ts +13 -6
  239. package/dist/chunk-2XIVXWHA.mjs +0 -1930
  240. package/dist/chunk-3INS3PR5.mjs +0 -884
  241. package/dist/chunk-3OVABDRH.mjs +0 -17096
  242. package/dist/chunk-7RFRWDCW.mjs +0 -1504
  243. package/dist/chunk-DLDWZFYC.mjs +0 -1495
  244. package/dist/chunk-E6SZWREQ.mjs +0 -57
  245. package/dist/chunk-F6F73W35.mjs +0 -16166
  246. package/dist/chunk-G33LB27A.mjs +0 -16166
  247. package/dist/chunk-HGU6HZRC.mjs +0 -231
  248. package/dist/chunk-L2K34JCU.mjs +0 -1496
  249. package/dist/chunk-OFDBEIEK.mjs +0 -16166
  250. package/dist/chunk-SF7YSLF5.mjs +0 -1515
  251. package/dist/chunk-SN4ZDTVW.mjs +0 -16166
  252. package/dist/chunk-WWUSGOXE.mjs +0 -17129
  253. package/dist/constants-VOI7BSLK.mjs +0 -27
  254. package/dist/index-B71aXVzk.d.ts +0 -13264
  255. package/dist/index-BYZbDjal.d.ts +0 -11390
  256. package/dist/index-CHB3KuOB.d.mts +0 -11859
  257. package/dist/index-CzWPI6Le.d.ts +0 -11859
  258. package/dist/index-pOIIuwfV.d.mts +0 -13264
  259. package/dist/index-xbWjohNq.d.mts +0 -11390
  260. package/dist/solana-4O4K45VU.mjs +0 -46
  261. package/dist/solana-5EMCTPTS.mjs +0 -46
  262. package/dist/solana-NDABAZ6P.mjs +0 -56
  263. package/dist/solana-Q4NAVBTS.mjs +0 -46
  264. package/dist/solana-ZYO63LY5.mjs +0 -46
@@ -0,0 +1,233 @@
1
+ /**
2
+ * Stealth Address Module
3
+ *
4
+ * Implements EIP-5564 style stealth addresses for multiple curves.
5
+ *
6
+ * Flow:
7
+ * 1. Recipient generates stealth meta-address (spending key P, viewing key Q)
8
+ * 2. Sender generates ephemeral keypair (r, R = r*G)
9
+ * 3. Sender computes shared secret: S = r * P
10
+ * 4. Sender derives stealth address: A = Q + hash(S)*G
11
+ * 5. Recipient scans: for each R, compute S = p * R, check if A matches
12
+ *
13
+ * @module stealth
14
+ */
15
+
16
+ import type {
17
+ StealthMetaAddress,
18
+ StealthAddress,
19
+ StealthAddressRecovery,
20
+ ChainId,
21
+ HexString,
22
+ } from '@sip-protocol/types'
23
+ import { ValidationError } from '../errors'
24
+ import { isValidChainId } from '../validation'
25
+
26
+ // Import curve-specific implementations
27
+ import {
28
+ isEd25519Chain,
29
+ getCurveForChain,
30
+ generateEd25519StealthMetaAddress,
31
+ generateEd25519StealthAddress,
32
+ deriveEd25519StealthPrivateKey,
33
+ checkEd25519StealthAddress,
34
+ } from './ed25519'
35
+
36
+ import {
37
+ generateSecp256k1StealthMetaAddress,
38
+ generateSecp256k1StealthAddress,
39
+ deriveSecp256k1StealthPrivateKey,
40
+ checkSecp256k1StealthAddress,
41
+ publicKeyToEthAddress,
42
+ validateSecp256k1StealthMetaAddress,
43
+ validateSecp256k1StealthAddress,
44
+ } from './secp256k1'
45
+
46
+ import {
47
+ encodeStealthMetaAddress,
48
+ decodeStealthMetaAddress,
49
+ validateStealthMetaAddress,
50
+ parseStealthAddress,
51
+ } from './meta-address'
52
+
53
+ import {
54
+ ed25519PublicKeyToSolanaAddress,
55
+ solanaAddressToEd25519PublicKey,
56
+ isValidSolanaAddress,
57
+ ed25519PublicKeyToNearAddress,
58
+ nearAddressToEd25519PublicKey,
59
+ isValidNearImplicitAddress,
60
+ isValidNearAccountId,
61
+ } from './address-derivation'
62
+
63
+ // Re-export types
64
+ export type { StealthCurve } from './ed25519'
65
+
66
+ // Re-export utility functions for tests and advanced use cases
67
+ export {
68
+ bytesToBigInt,
69
+ bigIntToBytes,
70
+ bytesToBigIntLE,
71
+ bigIntToBytesLE,
72
+ bytesToBase58,
73
+ base58ToBytes,
74
+ toChecksumAddress,
75
+ ED25519_ORDER,
76
+ ED25519_CHAINS,
77
+ getEd25519Scalar,
78
+ } from './utils'
79
+
80
+ // ─── Unified API ────────────────────────────────────────────────────────────
81
+
82
+ /**
83
+ * Generate a new stealth meta-address keypair for receiving private payments
84
+ *
85
+ * Automatically dispatches to the correct curve implementation based on chain.
86
+ * - secp256k1 for: ethereum, polygon, arbitrum, optimism, base, bitcoin, zcash
87
+ * - ed25519 for: solana, near, aptos, sui
88
+ *
89
+ * @param chain - Target blockchain network
90
+ * @param label - Optional human-readable label
91
+ * @returns Stealth meta-address and private keys
92
+ * @throws {ValidationError} If chain is invalid
93
+ */
94
+ export function generateStealthMetaAddress(
95
+ chain: ChainId,
96
+ label?: string,
97
+ ): {
98
+ metaAddress: StealthMetaAddress
99
+ spendingPrivateKey: HexString
100
+ viewingPrivateKey: HexString
101
+ } {
102
+ if (!isValidChainId(chain)) {
103
+ throw new ValidationError(
104
+ `invalid chain '${chain}', must be one of: solana, ethereum, near, zcash, polygon, arbitrum, optimism, base, bitcoin, aptos, sui, cosmos, osmosis, injective, celestia, sei, dydx`,
105
+ 'chain'
106
+ )
107
+ }
108
+
109
+ if (isEd25519Chain(chain)) {
110
+ return generateEd25519StealthMetaAddress(chain, label)
111
+ }
112
+
113
+ return generateSecp256k1StealthMetaAddress(chain, label)
114
+ }
115
+
116
+ /**
117
+ * Generate a one-time stealth address for sending funds to a recipient
118
+ *
119
+ * Automatically dispatches to the correct curve implementation based on chain.
120
+ *
121
+ * @param recipientMetaAddress - Recipient's public stealth meta-address
122
+ * @returns Stealth address data for publication
123
+ * @throws {ValidationError} If meta-address is invalid
124
+ */
125
+ export function generateStealthAddress(
126
+ recipientMetaAddress: StealthMetaAddress,
127
+ ): {
128
+ stealthAddress: StealthAddress
129
+ sharedSecret: HexString
130
+ } {
131
+ validateStealthMetaAddress(recipientMetaAddress)
132
+
133
+ if (isEd25519Chain(recipientMetaAddress.chain)) {
134
+ return generateEd25519StealthAddress(recipientMetaAddress)
135
+ }
136
+
137
+ return generateSecp256k1StealthAddress(recipientMetaAddress)
138
+ }
139
+
140
+ /**
141
+ * Derive the private key for a stealth address (for recipient to claim funds)
142
+ *
143
+ * Automatically dispatches to the correct curve implementation.
144
+ *
145
+ * @param stealthAddress - The stealth address to recover
146
+ * @param spendingPrivateKey - Recipient's spending private key
147
+ * @param viewingPrivateKey - Recipient's viewing private key
148
+ * @returns Recovery data including derived private key
149
+ * @throws {ValidationError} If any input is invalid
150
+ */
151
+ export function deriveStealthPrivateKey(
152
+ stealthAddress: StealthAddress,
153
+ spendingPrivateKey: HexString,
154
+ viewingPrivateKey: HexString,
155
+ ): StealthAddressRecovery {
156
+ // Try to detect curve from address length
157
+ // ed25519: 32 bytes (64 hex chars), secp256k1: 33 bytes (66 hex chars)
158
+ const addressHex = stealthAddress.address.slice(2)
159
+
160
+ if (addressHex.length === 64) {
161
+ // 32 bytes = ed25519
162
+ return deriveEd25519StealthPrivateKey(stealthAddress, spendingPrivateKey, viewingPrivateKey)
163
+ }
164
+
165
+ // Default to secp256k1
166
+ return deriveSecp256k1StealthPrivateKey(stealthAddress, spendingPrivateKey, viewingPrivateKey)
167
+ }
168
+
169
+ /**
170
+ * Check if a stealth address was intended for this recipient
171
+ *
172
+ * Automatically dispatches to the correct curve implementation.
173
+ *
174
+ * @param stealthAddress - Stealth address to check
175
+ * @param spendingPrivateKey - Recipient's spending private key
176
+ * @param viewingPrivateKey - Recipient's viewing private key
177
+ * @returns true if this address belongs to the recipient
178
+ * @throws {ValidationError} If any input is invalid
179
+ */
180
+ export function checkStealthAddress(
181
+ stealthAddress: StealthAddress,
182
+ spendingPrivateKey: HexString,
183
+ viewingPrivateKey: HexString,
184
+ ): boolean {
185
+ // Try to detect curve from address length
186
+ const addressHex = stealthAddress.address.slice(2)
187
+
188
+ if (addressHex.length === 64) {
189
+ // 32 bytes = ed25519
190
+ return checkEd25519StealthAddress(stealthAddress, spendingPrivateKey, viewingPrivateKey)
191
+ }
192
+
193
+ // Default to secp256k1
194
+ return checkSecp256k1StealthAddress(stealthAddress, spendingPrivateKey, viewingPrivateKey)
195
+ }
196
+
197
+ // ─── Re-exports ─────────────────────────────────────────────────────────────
198
+
199
+ // Chain detection
200
+ export { isEd25519Chain, getCurveForChain }
201
+
202
+ // ed25519 (Solana, NEAR, Aptos, Sui)
203
+ export {
204
+ generateEd25519StealthMetaAddress,
205
+ generateEd25519StealthAddress,
206
+ deriveEd25519StealthPrivateKey,
207
+ checkEd25519StealthAddress,
208
+ }
209
+
210
+ // secp256k1 (Ethereum, Polygon, etc.)
211
+ export { publicKeyToEthAddress }
212
+
213
+ // Meta-address encoding
214
+ export {
215
+ encodeStealthMetaAddress,
216
+ decodeStealthMetaAddress,
217
+ parseStealthAddress,
218
+ }
219
+
220
+ // Solana address derivation
221
+ export {
222
+ ed25519PublicKeyToSolanaAddress,
223
+ solanaAddressToEd25519PublicKey,
224
+ isValidSolanaAddress,
225
+ }
226
+
227
+ // NEAR address derivation
228
+ export {
229
+ ed25519PublicKeyToNearAddress,
230
+ nearAddressToEd25519PublicKey,
231
+ isValidNearImplicitAddress,
232
+ isValidNearAccountId,
233
+ }
@@ -0,0 +1,221 @@
1
+ /**
2
+ * Stealth Meta-Address Encoding/Decoding
3
+ *
4
+ * Functions for encoding and decoding stealth meta-addresses.
5
+ */
6
+
7
+ import type { StealthMetaAddress, StealthAddress, ChainId, HexString } from '@sip-protocol/types'
8
+ import { ValidationError } from '../errors'
9
+ import {
10
+ isValidChainId,
11
+ isValidCompressedPublicKey,
12
+ isValidEd25519PublicKey,
13
+ } from '../validation'
14
+ import { isEd25519Chain } from './ed25519'
15
+
16
+ // ─── Meta-Address Encoding ──────────────────────────────────────────────────
17
+
18
+ /**
19
+ * Encode a stealth meta-address as a string
20
+ * Format: sip:{chain}:{spendingKey}:{viewingKey}
21
+ */
22
+ export function encodeStealthMetaAddress(metaAddress: StealthMetaAddress): string {
23
+ return `sip:${metaAddress.chain}:${metaAddress.spendingKey}:${metaAddress.viewingKey}`
24
+ }
25
+
26
+ /**
27
+ * Decode a stealth meta-address from a string
28
+ *
29
+ * @param encoded - Encoded stealth meta-address (format: sip:<chain>:<spendingKey>:<viewingKey>)
30
+ * @returns Decoded StealthMetaAddress
31
+ * @throws {ValidationError} If format is invalid or keys are malformed
32
+ */
33
+ export function decodeStealthMetaAddress(encoded: string): StealthMetaAddress {
34
+ if (typeof encoded !== 'string') {
35
+ throw new ValidationError('must be a string', 'encoded')
36
+ }
37
+
38
+ const parts = encoded.split(':')
39
+ if (parts.length < 4 || parts[0] !== 'sip') {
40
+ throw new ValidationError(
41
+ 'invalid format, expected: sip:<chain>:<spendingKey>:<viewingKey>',
42
+ 'encoded'
43
+ )
44
+ }
45
+
46
+ const [, chain, spendingKey, viewingKey] = parts
47
+
48
+ // Validate chain
49
+ if (!isValidChainId(chain)) {
50
+ throw new ValidationError(
51
+ `invalid chain '${chain}'`,
52
+ 'encoded.chain'
53
+ )
54
+ }
55
+
56
+ // Validate keys based on chain's curve type
57
+ const chainId = chain as ChainId
58
+ if (isEd25519Chain(chainId)) {
59
+ // Ed25519 chains (Solana, NEAR) use 32-byte public keys
60
+ if (!isValidEd25519PublicKey(spendingKey)) {
61
+ throw new ValidationError(
62
+ 'spendingKey must be a valid 32-byte ed25519 public key',
63
+ 'encoded.spendingKey'
64
+ )
65
+ }
66
+
67
+ if (!isValidEd25519PublicKey(viewingKey)) {
68
+ throw new ValidationError(
69
+ 'viewingKey must be a valid 32-byte ed25519 public key',
70
+ 'encoded.viewingKey'
71
+ )
72
+ }
73
+ } else {
74
+ // secp256k1 chains (Ethereum, etc.) use 33-byte compressed public keys
75
+ if (!isValidCompressedPublicKey(spendingKey)) {
76
+ throw new ValidationError(
77
+ 'spendingKey must be a valid compressed secp256k1 public key',
78
+ 'encoded.spendingKey'
79
+ )
80
+ }
81
+
82
+ if (!isValidCompressedPublicKey(viewingKey)) {
83
+ throw new ValidationError(
84
+ 'viewingKey must be a valid compressed secp256k1 public key',
85
+ 'encoded.viewingKey'
86
+ )
87
+ }
88
+ }
89
+
90
+ return {
91
+ chain: chain as ChainId,
92
+ spendingKey: spendingKey as HexString,
93
+ viewingKey: viewingKey as HexString,
94
+ }
95
+ }
96
+
97
+ // ─── Multi-Curve Meta-Address Validation ────────────────────────────────────
98
+
99
+ /**
100
+ * Validate a StealthMetaAddress object
101
+ * Supports both secp256k1 (EVM chains) and ed25519 (Solana, NEAR, etc.) key formats
102
+ */
103
+ export function validateStealthMetaAddress(
104
+ metaAddress: StealthMetaAddress,
105
+ field: string = 'recipientMetaAddress'
106
+ ): void {
107
+ if (!metaAddress || typeof metaAddress !== 'object') {
108
+ throw new ValidationError('must be an object', field)
109
+ }
110
+
111
+ // Validate chain
112
+ if (!isValidChainId(metaAddress.chain)) {
113
+ throw new ValidationError(
114
+ `invalid chain '${metaAddress.chain}'`,
115
+ `${field}.chain`
116
+ )
117
+ }
118
+
119
+ // Determine key type based on chain (ed25519 vs secp256k1)
120
+ const isEd25519 = isEd25519Chain(metaAddress.chain)
121
+
122
+ if (isEd25519) {
123
+ // Ed25519 chains (Solana, NEAR, Aptos, Sui) use 32-byte public keys
124
+ if (!isValidEd25519PublicKey(metaAddress.spendingKey)) {
125
+ throw new ValidationError(
126
+ 'spendingKey must be a valid ed25519 public key (32 bytes)',
127
+ `${field}.spendingKey`
128
+ )
129
+ }
130
+ if (!isValidEd25519PublicKey(metaAddress.viewingKey)) {
131
+ throw new ValidationError(
132
+ 'viewingKey must be a valid ed25519 public key (32 bytes)',
133
+ `${field}.viewingKey`
134
+ )
135
+ }
136
+ } else {
137
+ // Secp256k1 chains (Ethereum, etc.) use 33-byte compressed public keys
138
+ if (!isValidCompressedPublicKey(metaAddress.spendingKey)) {
139
+ throw new ValidationError(
140
+ 'spendingKey must be a valid compressed secp256k1 public key (33 bytes, starting with 02 or 03)',
141
+ `${field}.spendingKey`
142
+ )
143
+ }
144
+ if (!isValidCompressedPublicKey(metaAddress.viewingKey)) {
145
+ throw new ValidationError(
146
+ 'viewingKey must be a valid compressed secp256k1 public key (33 bytes, starting with 02 or 03)',
147
+ `${field}.viewingKey`
148
+ )
149
+ }
150
+ }
151
+ }
152
+
153
+ // ─── Stealth Address Parsing ────────────────────────────────────────────────
154
+
155
+ /**
156
+ * Parse a stealth address string into its components
157
+ *
158
+ * Format: `<stealthAddress>:<ephemeralPublicKey>:<viewTag>`
159
+ */
160
+ export function parseStealthAddress(input: string): StealthAddress {
161
+ if (!input || typeof input !== 'string') {
162
+ throw new ValidationError(
163
+ 'stealth address input must be a non-empty string',
164
+ 'input'
165
+ )
166
+ }
167
+
168
+ const parts = input.split(':')
169
+ if (parts.length !== 3) {
170
+ throw new ValidationError(
171
+ 'invalid stealth address format. Expected: <address>:<ephemeralPublicKey>:<viewTag>',
172
+ 'input'
173
+ )
174
+ }
175
+
176
+ const [address, ephemeralPublicKey, viewTagHex] = parts
177
+
178
+ // Validate address (basic check - hex or base58)
179
+ if (!address || address.length < 20) {
180
+ throw new ValidationError(
181
+ 'invalid stealth address: too short',
182
+ 'address'
183
+ )
184
+ }
185
+
186
+ // Validate ephemeral public key (hex or base58)
187
+ if (!ephemeralPublicKey || ephemeralPublicKey.length < 20) {
188
+ throw new ValidationError(
189
+ 'invalid ephemeral public key: too short',
190
+ 'ephemeralPublicKey'
191
+ )
192
+ }
193
+
194
+ // Validate view tag (1-2 hex chars, 0-255)
195
+ if (!viewTagHex || viewTagHex.length > 2 || !/^[0-9a-fA-F]+$/.test(viewTagHex)) {
196
+ throw new ValidationError(
197
+ 'invalid view tag: must be 1-2 hex characters (0-255)',
198
+ 'viewTag'
199
+ )
200
+ }
201
+
202
+ const viewTag = parseInt(viewTagHex, 16)
203
+ if (viewTag < 0 || viewTag > 255) {
204
+ throw new ValidationError(
205
+ 'view tag must be in range 0-255',
206
+ 'viewTag'
207
+ )
208
+ }
209
+
210
+ // Normalize address to hex format if needed
211
+ const normalizedAddress = address.startsWith('0x') ? address : `0x${address}`
212
+ const normalizedEphemeral = ephemeralPublicKey.startsWith('0x')
213
+ ? ephemeralPublicKey
214
+ : `0x${ephemeralPublicKey}`
215
+
216
+ return {
217
+ address: normalizedAddress as HexString,
218
+ ephemeralPublicKey: normalizedEphemeral as HexString,
219
+ viewTag,
220
+ }
221
+ }