@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,455 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ethereum Viewing Key Management (EIP-5564)
|
|
3
|
+
*
|
|
4
|
+
* Viewing keys enable selective disclosure for compliance and auditing.
|
|
5
|
+
* The viewing key holder can scan for incoming payments but cannot spend funds.
|
|
6
|
+
*
|
|
7
|
+
* ## Use Cases
|
|
8
|
+
*
|
|
9
|
+
* 1. **Self-Scanning**: Recipient uses viewing key to find incoming payments
|
|
10
|
+
* 2. **Audit/Compliance**: Share viewing key with auditors for transaction visibility
|
|
11
|
+
* 3. **Watch-Only Wallets**: Monitor stealth addresses without spending capability
|
|
12
|
+
*
|
|
13
|
+
* ## Security Model
|
|
14
|
+
*
|
|
15
|
+
* - Viewing key = can see incoming payments, cannot spend
|
|
16
|
+
* - Spending key = required to claim/spend funds
|
|
17
|
+
* - Both keys derive from the same meta-address
|
|
18
|
+
*
|
|
19
|
+
* @packageDocumentation
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { secp256k1 } from '@noble/curves/secp256k1'
|
|
23
|
+
import { sha256 } from '@noble/hashes/sha256'
|
|
24
|
+
import { bytesToHex, randomBytes } from '@noble/hashes/utils'
|
|
25
|
+
import type { HexString, StealthMetaAddress } from '@sip-protocol/types'
|
|
26
|
+
import { ValidationError } from '../../errors'
|
|
27
|
+
import { isValidHexLength, isValidPrivateKey } from '../../validation'
|
|
28
|
+
import type {
|
|
29
|
+
EthereumViewingKeyExport,
|
|
30
|
+
EthereumViewingKeyPair,
|
|
31
|
+
EthereumPrivacyLevel,
|
|
32
|
+
} from './types'
|
|
33
|
+
import type { EthereumNetwork } from './constants'
|
|
34
|
+
|
|
35
|
+
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Viewing key disclosure scope
|
|
39
|
+
*/
|
|
40
|
+
export type ViewingKeyScope =
|
|
41
|
+
| 'all' // Can see all transactions
|
|
42
|
+
| 'incoming' // Can see incoming only
|
|
43
|
+
| 'range' // Can see transactions in block range
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Viewing key permissions
|
|
47
|
+
*/
|
|
48
|
+
export interface ViewingKeyPermissions {
|
|
49
|
+
/** Can view incoming payments */
|
|
50
|
+
canViewIncoming: boolean
|
|
51
|
+
/** Can view outgoing payments (requires additional data) */
|
|
52
|
+
canViewOutgoing: boolean
|
|
53
|
+
/** Can view transaction amounts (vs just detecting payments) */
|
|
54
|
+
canViewAmounts: boolean
|
|
55
|
+
/** Block range restriction (if scope is 'range') */
|
|
56
|
+
blockRange?: {
|
|
57
|
+
from: number
|
|
58
|
+
to: number
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Shared viewing key for auditors
|
|
64
|
+
*/
|
|
65
|
+
export interface SharedViewingKey {
|
|
66
|
+
/** The viewing public key */
|
|
67
|
+
viewingPublicKey: HexString
|
|
68
|
+
/** The spending public key (for address verification) */
|
|
69
|
+
spendingPublicKey: HexString
|
|
70
|
+
/** Permissions granted */
|
|
71
|
+
permissions: ViewingKeyPermissions
|
|
72
|
+
/** Optional label */
|
|
73
|
+
label?: string
|
|
74
|
+
/** Expiration timestamp (ISO 8601) */
|
|
75
|
+
expiresAt?: string
|
|
76
|
+
/** Signature proving ownership (optional) */
|
|
77
|
+
signature?: HexString
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ─── Key Generation ─────────────────────────────────────────────────────────
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Generate a new viewing keypair
|
|
84
|
+
*
|
|
85
|
+
* @param spendingPublicKey - Associated spending public key
|
|
86
|
+
* @param label - Optional label
|
|
87
|
+
* @returns Viewing keypair
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* const viewingKey = generateViewingKeyPair(
|
|
92
|
+
* metaAddress.spendingKey,
|
|
93
|
+
* 'Main Wallet'
|
|
94
|
+
* )
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
export function generateViewingKeyPair(
|
|
98
|
+
spendingPublicKey: HexString,
|
|
99
|
+
label?: string
|
|
100
|
+
): EthereumViewingKeyPair {
|
|
101
|
+
// Generate random viewing private key
|
|
102
|
+
const viewingPrivateKey = randomBytes(32)
|
|
103
|
+
const viewingPublicKey = secp256k1.getPublicKey(viewingPrivateKey, true)
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
publicKey: `0x${bytesToHex(viewingPublicKey)}` as HexString,
|
|
107
|
+
privateKey: `0x${bytesToHex(viewingPrivateKey)}` as HexString,
|
|
108
|
+
spendingPublicKey,
|
|
109
|
+
label,
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Derive viewing public key from private key
|
|
115
|
+
*
|
|
116
|
+
* @param viewingPrivateKey - The viewing private key
|
|
117
|
+
* @returns Viewing public key
|
|
118
|
+
*/
|
|
119
|
+
export function deriveViewingPublicKey(viewingPrivateKey: HexString): HexString {
|
|
120
|
+
if (!isValidPrivateKey(viewingPrivateKey)) {
|
|
121
|
+
throw new ValidationError(
|
|
122
|
+
'must be a valid 32-byte hex string',
|
|
123
|
+
'viewingPrivateKey'
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const privateKeyBytes = hexToBytes(viewingPrivateKey.slice(2))
|
|
128
|
+
const publicKey = secp256k1.getPublicKey(privateKeyBytes, true)
|
|
129
|
+
|
|
130
|
+
return `0x${bytesToHex(publicKey)}` as HexString
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ─── Key Export/Import ──────────────────────────────────────────────────────
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Export a viewing key for sharing with auditors
|
|
137
|
+
*
|
|
138
|
+
* @param viewingKeyPair - The viewing keypair (only public parts exported)
|
|
139
|
+
* @param network - The Ethereum network
|
|
140
|
+
* @param expiresAt - Optional expiration timestamp
|
|
141
|
+
* @returns Exportable viewing key object
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```typescript
|
|
145
|
+
* const exported = exportViewingKey(viewingKey, 'mainnet')
|
|
146
|
+
* // Share 'exported' with auditor (contains no private keys)
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
export function exportViewingKey(
|
|
150
|
+
viewingKeyPair: EthereumViewingKeyPair,
|
|
151
|
+
network: EthereumNetwork,
|
|
152
|
+
expiresAt?: Date
|
|
153
|
+
): EthereumViewingKeyExport {
|
|
154
|
+
return {
|
|
155
|
+
version: 1,
|
|
156
|
+
chain: 'ethereum',
|
|
157
|
+
network,
|
|
158
|
+
viewingPublicKey: viewingKeyPair.publicKey,
|
|
159
|
+
spendingPublicKey: viewingKeyPair.spendingPublicKey,
|
|
160
|
+
label: viewingKeyPair.label,
|
|
161
|
+
createdAt: new Date().toISOString(),
|
|
162
|
+
expiresAt: expiresAt?.toISOString(),
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Import/parse an exported viewing key
|
|
168
|
+
*
|
|
169
|
+
* @param exported - The exported viewing key JSON
|
|
170
|
+
* @returns Parsed viewing key export
|
|
171
|
+
*/
|
|
172
|
+
export function importViewingKey(
|
|
173
|
+
exported: string | EthereumViewingKeyExport
|
|
174
|
+
): EthereumViewingKeyExport {
|
|
175
|
+
const data =
|
|
176
|
+
typeof exported === 'string'
|
|
177
|
+
? (JSON.parse(exported) as EthereumViewingKeyExport)
|
|
178
|
+
: exported
|
|
179
|
+
|
|
180
|
+
// Validate structure
|
|
181
|
+
if (data.version !== 1) {
|
|
182
|
+
throw new ValidationError(
|
|
183
|
+
`unsupported viewing key version: ${data.version}`,
|
|
184
|
+
'version'
|
|
185
|
+
)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (data.chain !== 'ethereum') {
|
|
189
|
+
throw new ValidationError(
|
|
190
|
+
`invalid chain: ${data.chain}, expected 'ethereum'`,
|
|
191
|
+
'chain'
|
|
192
|
+
)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (!isValidHexLength(data.viewingPublicKey, 33)) {
|
|
196
|
+
throw new ValidationError(
|
|
197
|
+
'viewingPublicKey must be a valid 33-byte hex string',
|
|
198
|
+
'viewingPublicKey'
|
|
199
|
+
)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (!isValidHexLength(data.spendingPublicKey, 33)) {
|
|
203
|
+
throw new ValidationError(
|
|
204
|
+
'spendingPublicKey must be a valid 33-byte hex string',
|
|
205
|
+
'spendingPublicKey'
|
|
206
|
+
)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return data
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Serialize a viewing key export to JSON string
|
|
214
|
+
*
|
|
215
|
+
* @param exportData - The viewing key export
|
|
216
|
+
* @returns JSON string
|
|
217
|
+
*/
|
|
218
|
+
export function serializeViewingKey(exportData: EthereumViewingKeyExport): string {
|
|
219
|
+
return JSON.stringify(exportData, null, 2)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// ─── Key Verification ───────────────────────────────────────────────────────
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Verify that a viewing key matches a meta-address
|
|
226
|
+
*
|
|
227
|
+
* @param viewingPublicKey - The viewing public key to verify
|
|
228
|
+
* @param metaAddress - The meta-address to check against
|
|
229
|
+
* @returns True if the viewing key matches
|
|
230
|
+
*/
|
|
231
|
+
export function verifyViewingKeyMatches(
|
|
232
|
+
viewingPublicKey: HexString,
|
|
233
|
+
metaAddress: StealthMetaAddress
|
|
234
|
+
): boolean {
|
|
235
|
+
// Normalize both keys (remove 0x prefix, lowercase)
|
|
236
|
+
const normalizedViewing = viewingPublicKey.slice(2).toLowerCase()
|
|
237
|
+
const normalizedMeta = metaAddress.viewingKey.slice(2).toLowerCase()
|
|
238
|
+
|
|
239
|
+
return normalizedViewing === normalizedMeta
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Check if a viewing key export has expired
|
|
244
|
+
*
|
|
245
|
+
* @param exportData - The viewing key export
|
|
246
|
+
* @returns True if expired
|
|
247
|
+
*/
|
|
248
|
+
export function isViewingKeyExpired(exportData: EthereumViewingKeyExport): boolean {
|
|
249
|
+
if (!exportData.expiresAt) {
|
|
250
|
+
return false
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const expiresAt = new Date(exportData.expiresAt)
|
|
254
|
+
return expiresAt < new Date()
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// ─── Shared Key Creation ────────────────────────────────────────────────────
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Create a shared viewing key with specific permissions
|
|
261
|
+
*
|
|
262
|
+
* @param viewingKeyPair - The full viewing keypair
|
|
263
|
+
* @param permissions - Permissions to grant
|
|
264
|
+
* @param expiresAt - Optional expiration
|
|
265
|
+
* @returns Shared viewing key for auditor
|
|
266
|
+
*
|
|
267
|
+
* @example
|
|
268
|
+
* ```typescript
|
|
269
|
+
* // Create a read-only viewing key for auditor
|
|
270
|
+
* const sharedKey = createSharedViewingKey(viewingKey, {
|
|
271
|
+
* canViewIncoming: true,
|
|
272
|
+
* canViewOutgoing: false,
|
|
273
|
+
* canViewAmounts: true,
|
|
274
|
+
* })
|
|
275
|
+
* ```
|
|
276
|
+
*/
|
|
277
|
+
export function createSharedViewingKey(
|
|
278
|
+
viewingKeyPair: EthereumViewingKeyPair,
|
|
279
|
+
permissions: ViewingKeyPermissions,
|
|
280
|
+
expiresAt?: Date
|
|
281
|
+
): SharedViewingKey {
|
|
282
|
+
return {
|
|
283
|
+
viewingPublicKey: viewingKeyPair.publicKey,
|
|
284
|
+
spendingPublicKey: viewingKeyPair.spendingPublicKey,
|
|
285
|
+
permissions,
|
|
286
|
+
label: viewingKeyPair.label,
|
|
287
|
+
expiresAt: expiresAt?.toISOString(),
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Create a full-access viewing key (for self-scanning)
|
|
293
|
+
*
|
|
294
|
+
* @param viewingKeyPair - The viewing keypair
|
|
295
|
+
* @returns Shared key with full permissions
|
|
296
|
+
*/
|
|
297
|
+
export function createFullAccessViewingKey(
|
|
298
|
+
viewingKeyPair: EthereumViewingKeyPair
|
|
299
|
+
): SharedViewingKey {
|
|
300
|
+
return createSharedViewingKey(viewingKeyPair, {
|
|
301
|
+
canViewIncoming: true,
|
|
302
|
+
canViewOutgoing: true,
|
|
303
|
+
canViewAmounts: true,
|
|
304
|
+
})
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Create a compliance-restricted viewing key
|
|
309
|
+
*
|
|
310
|
+
* @param viewingKeyPair - The viewing keypair
|
|
311
|
+
* @param fromBlock - Start block for visibility
|
|
312
|
+
* @param toBlock - End block for visibility
|
|
313
|
+
* @returns Shared key with block range restriction
|
|
314
|
+
*/
|
|
315
|
+
export function createRangeRestrictedViewingKey(
|
|
316
|
+
viewingKeyPair: EthereumViewingKeyPair,
|
|
317
|
+
fromBlock: number,
|
|
318
|
+
toBlock: number
|
|
319
|
+
): SharedViewingKey {
|
|
320
|
+
return createSharedViewingKey(viewingKeyPair, {
|
|
321
|
+
canViewIncoming: true,
|
|
322
|
+
canViewOutgoing: false,
|
|
323
|
+
canViewAmounts: true,
|
|
324
|
+
blockRange: { from: fromBlock, to: toBlock },
|
|
325
|
+
})
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// ─── Hash Functions ─────────────────────────────────────────────────────────
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Compute a hash of the viewing key for indexing/lookup
|
|
332
|
+
*
|
|
333
|
+
* @param viewingPublicKey - The viewing public key
|
|
334
|
+
* @returns Hash of the viewing key
|
|
335
|
+
*/
|
|
336
|
+
export function hashViewingKey(viewingPublicKey: HexString): HexString {
|
|
337
|
+
const keyBytes = hexToBytes(viewingPublicKey.slice(2))
|
|
338
|
+
const hash = sha256(keyBytes)
|
|
339
|
+
return `0x${bytesToHex(hash)}` as HexString
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Compute the viewing key hash used in on-chain registry
|
|
344
|
+
*
|
|
345
|
+
* @param viewingPublicKey - The viewing public key
|
|
346
|
+
* @param spendingPublicKey - The spending public key
|
|
347
|
+
* @returns Combined hash for registry lookup
|
|
348
|
+
*/
|
|
349
|
+
export function computeRegistryHash(
|
|
350
|
+
viewingPublicKey: HexString,
|
|
351
|
+
spendingPublicKey: HexString
|
|
352
|
+
): HexString {
|
|
353
|
+
const viewingBytes = hexToBytes(viewingPublicKey.slice(2))
|
|
354
|
+
const spendingBytes = hexToBytes(spendingPublicKey.slice(2))
|
|
355
|
+
|
|
356
|
+
// Concatenate and hash
|
|
357
|
+
const combined = new Uint8Array(viewingBytes.length + spendingBytes.length)
|
|
358
|
+
combined.set(viewingBytes, 0)
|
|
359
|
+
combined.set(spendingBytes, viewingBytes.length)
|
|
360
|
+
|
|
361
|
+
const hash = sha256(combined)
|
|
362
|
+
return `0x${bytesToHex(hash)}` as HexString
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// ─── Privacy Level Helpers ──────────────────────────────────────────────────
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Get the appropriate viewing key usage based on privacy level
|
|
369
|
+
*
|
|
370
|
+
* @param privacyLevel - The privacy level
|
|
371
|
+
* @returns Description of viewing key usage
|
|
372
|
+
*/
|
|
373
|
+
export function getViewingKeyUsage(
|
|
374
|
+
privacyLevel: EthereumPrivacyLevel
|
|
375
|
+
): {
|
|
376
|
+
required: boolean
|
|
377
|
+
shareable: boolean
|
|
378
|
+
description: string
|
|
379
|
+
} {
|
|
380
|
+
switch (privacyLevel) {
|
|
381
|
+
case 'transparent':
|
|
382
|
+
return {
|
|
383
|
+
required: false,
|
|
384
|
+
shareable: false,
|
|
385
|
+
description: 'No privacy - all transaction details are public',
|
|
386
|
+
}
|
|
387
|
+
case 'shielded':
|
|
388
|
+
return {
|
|
389
|
+
required: true,
|
|
390
|
+
shareable: false,
|
|
391
|
+
description: 'Full privacy - viewing key for self-scanning only',
|
|
392
|
+
}
|
|
393
|
+
case 'compliant':
|
|
394
|
+
return {
|
|
395
|
+
required: true,
|
|
396
|
+
shareable: true,
|
|
397
|
+
description: 'Privacy with compliance - viewing key can be shared with auditors',
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// ─── Utility Functions ──────────────────────────────────────────────────────
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Extract viewing key components from a meta-address
|
|
406
|
+
*
|
|
407
|
+
* @param metaAddress - The stealth meta-address
|
|
408
|
+
* @returns Viewing and spending public keys
|
|
409
|
+
*/
|
|
410
|
+
export function extractViewingComponents(metaAddress: StealthMetaAddress): {
|
|
411
|
+
viewingPublicKey: HexString
|
|
412
|
+
spendingPublicKey: HexString
|
|
413
|
+
} {
|
|
414
|
+
return {
|
|
415
|
+
viewingPublicKey: metaAddress.viewingKey,
|
|
416
|
+
spendingPublicKey: metaAddress.spendingKey,
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Validate viewing key permissions
|
|
422
|
+
*
|
|
423
|
+
* @param permissions - The permissions to validate
|
|
424
|
+
* @returns True if valid
|
|
425
|
+
*/
|
|
426
|
+
export function validatePermissions(permissions: ViewingKeyPermissions): boolean {
|
|
427
|
+
if (permissions.blockRange) {
|
|
428
|
+
if (permissions.blockRange.from < 0 || permissions.blockRange.to < 0) {
|
|
429
|
+
return false
|
|
430
|
+
}
|
|
431
|
+
if (permissions.blockRange.from > permissions.blockRange.to) {
|
|
432
|
+
return false
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// At least one permission should be granted
|
|
437
|
+
return (
|
|
438
|
+
permissions.canViewIncoming ||
|
|
439
|
+
permissions.canViewOutgoing ||
|
|
440
|
+
permissions.canViewAmounts
|
|
441
|
+
)
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// ─── Helper Functions ─────────────────────────────────────────────────────────
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Convert hex string to bytes
|
|
448
|
+
*/
|
|
449
|
+
function hexToBytes(hex: string): Uint8Array {
|
|
450
|
+
const bytes = new Uint8Array(hex.length / 2)
|
|
451
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
452
|
+
bytes[i] = parseInt(hex.substr(i * 2, 2), 16)
|
|
453
|
+
}
|
|
454
|
+
return bytes
|
|
455
|
+
}
|