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