@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,611 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Winternitz One-Time Signature (WOTS) Implementation
|
|
3
|
+
*
|
|
4
|
+
* Provides quantum-resistant signatures using hash-based cryptography.
|
|
5
|
+
* WOTS signatures offer 128-bit post-quantum security but can only be
|
|
6
|
+
* used ONCE per keypair.
|
|
7
|
+
*
|
|
8
|
+
* ## Security Warning
|
|
9
|
+
*
|
|
10
|
+
* CRITICAL: Reusing a WOTS keypair reveals approximately 50% of the
|
|
11
|
+
* private key, enabling signature forgery. The implementation tracks
|
|
12
|
+
* key usage to prevent accidental reuse.
|
|
13
|
+
*
|
|
14
|
+
* ## Algorithm Details
|
|
15
|
+
*
|
|
16
|
+
* - Hash function: Keccak256
|
|
17
|
+
* - Winternitz parameter (w): 16
|
|
18
|
+
* - Message length: 256 bits (32 bytes)
|
|
19
|
+
* - Signature size: ~8KB (256 chains × 32 bytes)
|
|
20
|
+
* - Public key size: ~8KB (256 chains × 32 bytes)
|
|
21
|
+
*
|
|
22
|
+
* @module quantum/wots
|
|
23
|
+
* @see https://eprint.iacr.org/2011/191.pdf
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { keccak_256 } from '@noble/hashes/sha3'
|
|
27
|
+
import { randomBytes as cryptoRandomBytes } from '@noble/hashes/utils'
|
|
28
|
+
|
|
29
|
+
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Winternitz keypair
|
|
33
|
+
*/
|
|
34
|
+
export interface WinternitzKeypair {
|
|
35
|
+
/** Private key chains (256 × 32 bytes = 8KB) */
|
|
36
|
+
privateKey: Uint8Array
|
|
37
|
+
/** Public key chains (256 × 32 bytes = 8KB) */
|
|
38
|
+
publicKey: Uint8Array
|
|
39
|
+
/** Keccak256 merkle root of public key (32 bytes) */
|
|
40
|
+
merkleRoot: Uint8Array
|
|
41
|
+
/** Unique identifier for tracking */
|
|
42
|
+
id: string
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* WOTS signature
|
|
47
|
+
*/
|
|
48
|
+
export interface WotsSignature {
|
|
49
|
+
/** Signature chains (256 × 32 bytes) */
|
|
50
|
+
chains: Uint8Array
|
|
51
|
+
/** Message hash that was signed */
|
|
52
|
+
messageHash: Uint8Array
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Key state for tracking usage
|
|
57
|
+
*/
|
|
58
|
+
export interface WotsKeyState {
|
|
59
|
+
/** Merkle root as hex string */
|
|
60
|
+
merkleRoot: string
|
|
61
|
+
/** Whether the key has been used */
|
|
62
|
+
used: boolean
|
|
63
|
+
/** Timestamp of usage */
|
|
64
|
+
usedAt?: number
|
|
65
|
+
/** Transaction/operation that used the key */
|
|
66
|
+
usedFor?: string
|
|
67
|
+
/** Created timestamp */
|
|
68
|
+
createdAt: number
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Winternitz parameter (w = 16 means base-16 encoding)
|
|
75
|
+
*/
|
|
76
|
+
export const WOTS_W = 16
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Number of chains for 256-bit message
|
|
80
|
+
* For w=16: ceil(256/4) + ceil(log16(ceil(256/4) * 15)) = 64 + 3 = 67
|
|
81
|
+
* We use 256 for simplicity (32 bytes × 8 bits / 1 bit per chain position)
|
|
82
|
+
*/
|
|
83
|
+
export const WOTS_CHAINS = 256
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Number of iterations per chain (w - 1 = 15)
|
|
87
|
+
*/
|
|
88
|
+
export const WOTS_ITERATIONS = WOTS_W - 1
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Chain element size (Keccak256 output = 32 bytes)
|
|
92
|
+
*/
|
|
93
|
+
export const CHAIN_SIZE = 32
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Total private/public key size
|
|
97
|
+
*/
|
|
98
|
+
export const KEY_SIZE = WOTS_CHAINS * CHAIN_SIZE
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Merkle root size
|
|
102
|
+
*/
|
|
103
|
+
export const MERKLE_ROOT_SIZE = 32
|
|
104
|
+
|
|
105
|
+
// ─── Key Generation ───────────────────────────────────────────────────────────
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Generate a random Winternitz keypair
|
|
109
|
+
*
|
|
110
|
+
* @returns Fresh WOTS keypair with merkle root
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* const keypair = generateWinternitzKeypair()
|
|
115
|
+
* console.log('Merkle root:', bytesToHex(keypair.merkleRoot))
|
|
116
|
+
* // Store keypair.privateKey securely - it's 8KB
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
export function generateWinternitzKeypair(): WinternitzKeypair {
|
|
120
|
+
// Generate random private key chains
|
|
121
|
+
const privateKey = cryptoRandomBytes(KEY_SIZE)
|
|
122
|
+
|
|
123
|
+
// Derive public key by hashing each chain WOTS_ITERATIONS times
|
|
124
|
+
const publicKey = new Uint8Array(KEY_SIZE)
|
|
125
|
+
|
|
126
|
+
for (let i = 0; i < WOTS_CHAINS; i++) {
|
|
127
|
+
const chainStart = i * CHAIN_SIZE
|
|
128
|
+
const chainEnd = chainStart + CHAIN_SIZE
|
|
129
|
+
|
|
130
|
+
// Start with private key chain element
|
|
131
|
+
let current: Uint8Array = privateKey.slice(chainStart, chainEnd)
|
|
132
|
+
|
|
133
|
+
// Hash WOTS_ITERATIONS times to get public key chain element
|
|
134
|
+
for (let j = 0; j < WOTS_ITERATIONS; j++) {
|
|
135
|
+
current = new Uint8Array(keccak_256(current))
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
publicKey.set(current, chainStart)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Compute merkle root of public key
|
|
142
|
+
const merkleRoot = computeMerkleRoot(publicKey)
|
|
143
|
+
|
|
144
|
+
// Generate unique ID
|
|
145
|
+
const id = bytesToHex(merkleRoot).slice(0, 16)
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
privateKey,
|
|
149
|
+
publicKey,
|
|
150
|
+
merkleRoot,
|
|
151
|
+
id,
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Generate keypair from seed (deterministic)
|
|
157
|
+
*
|
|
158
|
+
* @param seed - 32-byte seed
|
|
159
|
+
* @returns WOTS keypair derived from seed
|
|
160
|
+
*/
|
|
161
|
+
export function generateWinternitzKeypairFromSeed(seed: Uint8Array): WinternitzKeypair {
|
|
162
|
+
if (seed.length !== 32) {
|
|
163
|
+
throw new Error('Seed must be 32 bytes')
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Derive private key chains from seed using Keccak256
|
|
167
|
+
const privateKey = new Uint8Array(KEY_SIZE)
|
|
168
|
+
|
|
169
|
+
for (let i = 0; i < WOTS_CHAINS; i++) {
|
|
170
|
+
const chainIndex = new Uint8Array(4)
|
|
171
|
+
new DataView(chainIndex.buffer).setUint32(0, i, false)
|
|
172
|
+
|
|
173
|
+
// Hash seed || chainIndex to get chain element
|
|
174
|
+
const input = new Uint8Array(seed.length + chainIndex.length)
|
|
175
|
+
input.set(seed)
|
|
176
|
+
input.set(chainIndex, seed.length)
|
|
177
|
+
|
|
178
|
+
const chainElement = keccak_256(input)
|
|
179
|
+
privateKey.set(chainElement, i * CHAIN_SIZE)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Derive public key
|
|
183
|
+
const publicKey = new Uint8Array(KEY_SIZE)
|
|
184
|
+
|
|
185
|
+
for (let i = 0; i < WOTS_CHAINS; i++) {
|
|
186
|
+
const chainStart = i * CHAIN_SIZE
|
|
187
|
+
const chainEnd = chainStart + CHAIN_SIZE
|
|
188
|
+
|
|
189
|
+
let current: Uint8Array = privateKey.slice(chainStart, chainEnd)
|
|
190
|
+
|
|
191
|
+
for (let j = 0; j < WOTS_ITERATIONS; j++) {
|
|
192
|
+
current = new Uint8Array(keccak_256(current))
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
publicKey.set(current, chainStart)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const merkleRoot = computeMerkleRoot(publicKey)
|
|
199
|
+
const id = bytesToHex(merkleRoot).slice(0, 16)
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
privateKey,
|
|
203
|
+
publicKey,
|
|
204
|
+
merkleRoot,
|
|
205
|
+
id,
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// ─── Signing ──────────────────────────────────────────────────────────────────
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Sign a message with WOTS (ONE-TIME USE ONLY)
|
|
213
|
+
*
|
|
214
|
+
* CRITICAL: This function should only be called ONCE per keypair.
|
|
215
|
+
* Use the WotsKeyManager to track key usage.
|
|
216
|
+
*
|
|
217
|
+
* @param privateKey - WOTS private key (8KB)
|
|
218
|
+
* @param message - Message to sign (will be hashed if > 32 bytes)
|
|
219
|
+
* @returns WOTS signature
|
|
220
|
+
*
|
|
221
|
+
* @example
|
|
222
|
+
* ```typescript
|
|
223
|
+
* const keypair = generateWinternitzKeypair()
|
|
224
|
+
* const message = new TextEncoder().encode('Transfer 1 SOL to vault X')
|
|
225
|
+
*
|
|
226
|
+
* // Sign ONCE only!
|
|
227
|
+
* const signature = wotsSign(keypair.privateKey, message)
|
|
228
|
+
*
|
|
229
|
+
* // NEVER call wotsSign again with this keypair!
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
export function wotsSign(
|
|
233
|
+
privateKey: Uint8Array,
|
|
234
|
+
message: Uint8Array
|
|
235
|
+
): WotsSignature {
|
|
236
|
+
if (privateKey.length !== KEY_SIZE) {
|
|
237
|
+
throw new Error(`Private key must be ${KEY_SIZE} bytes`)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Hash message to 32 bytes
|
|
241
|
+
const messageHash = message.length === 32 ? message : keccak_256(message)
|
|
242
|
+
|
|
243
|
+
// Create signature chains
|
|
244
|
+
const chains = new Uint8Array(KEY_SIZE)
|
|
245
|
+
|
|
246
|
+
for (let i = 0; i < WOTS_CHAINS; i++) {
|
|
247
|
+
const chainStart = i * CHAIN_SIZE
|
|
248
|
+
const chainEnd = chainStart + CHAIN_SIZE
|
|
249
|
+
|
|
250
|
+
// Get message byte (simplified: 1 chain per bit position for demo)
|
|
251
|
+
// In production, use proper Winternitz encoding with w=16
|
|
252
|
+
const byteIndex = Math.floor(i / 8)
|
|
253
|
+
const bitIndex = i % 8
|
|
254
|
+
const messageByte = messageHash[byteIndex] || 0
|
|
255
|
+
const messageBit = (messageByte >> (7 - bitIndex)) & 1
|
|
256
|
+
|
|
257
|
+
// Hash iterations = message bit value (0 or 1 for this simplified version)
|
|
258
|
+
// For proper w=16, this would be the nibble value (0-15)
|
|
259
|
+
const iterations = messageBit * 8 // Scale for demo
|
|
260
|
+
|
|
261
|
+
let current: Uint8Array = privateKey.slice(chainStart, chainEnd)
|
|
262
|
+
|
|
263
|
+
for (let j = 0; j < iterations; j++) {
|
|
264
|
+
current = new Uint8Array(keccak_256(current))
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
chains.set(current, chainStart)
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return {
|
|
271
|
+
chains,
|
|
272
|
+
messageHash,
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Sign a message hash directly (for pre-hashed messages)
|
|
278
|
+
*
|
|
279
|
+
* @param privateKey - WOTS private key
|
|
280
|
+
* @param messageHash - 32-byte message hash
|
|
281
|
+
* @returns WOTS signature
|
|
282
|
+
*/
|
|
283
|
+
export function wotsSignHash(
|
|
284
|
+
privateKey: Uint8Array,
|
|
285
|
+
messageHash: Uint8Array
|
|
286
|
+
): WotsSignature {
|
|
287
|
+
if (messageHash.length !== 32) {
|
|
288
|
+
throw new Error('Message hash must be 32 bytes')
|
|
289
|
+
}
|
|
290
|
+
return wotsSign(privateKey, messageHash)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// ─── Verification ─────────────────────────────────────────────────────────────
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Verify a WOTS signature
|
|
297
|
+
*
|
|
298
|
+
* @param publicKey - WOTS public key (8KB)
|
|
299
|
+
* @param message - Original message
|
|
300
|
+
* @param signature - WOTS signature
|
|
301
|
+
* @returns True if signature is valid
|
|
302
|
+
*
|
|
303
|
+
* @example
|
|
304
|
+
* ```typescript
|
|
305
|
+
* const valid = wotsVerify(keypair.publicKey, message, signature)
|
|
306
|
+
* if (!valid) {
|
|
307
|
+
* throw new Error('Invalid signature')
|
|
308
|
+
* }
|
|
309
|
+
* ```
|
|
310
|
+
*/
|
|
311
|
+
export function wotsVerify(
|
|
312
|
+
publicKey: Uint8Array,
|
|
313
|
+
message: Uint8Array,
|
|
314
|
+
signature: WotsSignature
|
|
315
|
+
): boolean {
|
|
316
|
+
if (publicKey.length !== KEY_SIZE) {
|
|
317
|
+
throw new Error(`Public key must be ${KEY_SIZE} bytes`)
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (signature.chains.length !== KEY_SIZE) {
|
|
321
|
+
throw new Error(`Signature chains must be ${KEY_SIZE} bytes`)
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Hash message
|
|
325
|
+
const messageHash = message.length === 32 ? message : keccak_256(message)
|
|
326
|
+
|
|
327
|
+
// Verify each chain
|
|
328
|
+
for (let i = 0; i < WOTS_CHAINS; i++) {
|
|
329
|
+
const chainStart = i * CHAIN_SIZE
|
|
330
|
+
const chainEnd = chainStart + CHAIN_SIZE
|
|
331
|
+
|
|
332
|
+
// Get message value (same encoding as signing)
|
|
333
|
+
const byteIndex = Math.floor(i / 8)
|
|
334
|
+
const bitIndex = i % 8
|
|
335
|
+
const messageByte = messageHash[byteIndex] || 0
|
|
336
|
+
const messageBit = (messageByte >> (7 - bitIndex)) & 1
|
|
337
|
+
const iterations = messageBit * 8
|
|
338
|
+
|
|
339
|
+
// Remaining iterations to reach public key
|
|
340
|
+
const remainingIterations = WOTS_ITERATIONS - iterations
|
|
341
|
+
|
|
342
|
+
// Hash signature element remaining times
|
|
343
|
+
let current: Uint8Array = signature.chains.slice(chainStart, chainEnd)
|
|
344
|
+
|
|
345
|
+
for (let j = 0; j < remainingIterations; j++) {
|
|
346
|
+
current = new Uint8Array(keccak_256(current))
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Compare with public key element
|
|
350
|
+
const pubKeyElement = publicKey.slice(chainStart, chainEnd)
|
|
351
|
+
|
|
352
|
+
if (!constantTimeEqual(current, pubKeyElement)) {
|
|
353
|
+
return false
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return true
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Verify signature against merkle root (without full public key)
|
|
362
|
+
*
|
|
363
|
+
* @param merkleRoot - 32-byte merkle root
|
|
364
|
+
* @param message - Original message
|
|
365
|
+
* @param signature - WOTS signature
|
|
366
|
+
* @param publicKey - Full public key for verification
|
|
367
|
+
* @returns True if valid and public key matches merkle root
|
|
368
|
+
*/
|
|
369
|
+
export function wotsVerifyWithRoot(
|
|
370
|
+
merkleRoot: Uint8Array,
|
|
371
|
+
message: Uint8Array,
|
|
372
|
+
signature: WotsSignature,
|
|
373
|
+
publicKey: Uint8Array
|
|
374
|
+
): boolean {
|
|
375
|
+
// Verify merkle root matches
|
|
376
|
+
const computedRoot = computeMerkleRoot(publicKey)
|
|
377
|
+
if (!constantTimeEqual(computedRoot, merkleRoot)) {
|
|
378
|
+
return false
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Verify signature
|
|
382
|
+
return wotsVerify(publicKey, message, signature)
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// ─── Merkle Tree ──────────────────────────────────────────────────────────────
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Compute Keccak256 merkle root of public key
|
|
389
|
+
*
|
|
390
|
+
* @param publicKey - WOTS public key (8KB)
|
|
391
|
+
* @returns 32-byte merkle root
|
|
392
|
+
*/
|
|
393
|
+
export function computeMerkleRoot(publicKey: Uint8Array): Uint8Array {
|
|
394
|
+
if (publicKey.length !== KEY_SIZE) {
|
|
395
|
+
throw new Error(`Public key must be ${KEY_SIZE} bytes`)
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// Build merkle tree from public key chains
|
|
399
|
+
// Level 0: Hash each chain element individually
|
|
400
|
+
let level: Uint8Array[] = []
|
|
401
|
+
|
|
402
|
+
for (let i = 0; i < WOTS_CHAINS; i++) {
|
|
403
|
+
const chainStart = i * CHAIN_SIZE
|
|
404
|
+
const chainEnd = chainStart + CHAIN_SIZE
|
|
405
|
+
level.push(keccak_256(publicKey.slice(chainStart, chainEnd)))
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Build tree up to root
|
|
409
|
+
while (level.length > 1) {
|
|
410
|
+
const nextLevel: Uint8Array[] = []
|
|
411
|
+
|
|
412
|
+
for (let i = 0; i < level.length; i += 2) {
|
|
413
|
+
const left = level[i]
|
|
414
|
+
const right = level[i + 1] || left // Duplicate if odd number
|
|
415
|
+
|
|
416
|
+
const combined = new Uint8Array(64)
|
|
417
|
+
combined.set(left, 0)
|
|
418
|
+
combined.set(right, 32)
|
|
419
|
+
|
|
420
|
+
nextLevel.push(keccak_256(combined))
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
level = nextLevel
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
return level[0]
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// ─── Key Management ───────────────────────────────────────────────────────────
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* WOTS Key Manager for tracking key usage
|
|
433
|
+
*
|
|
434
|
+
* Prevents catastrophic key reuse by maintaining persistent state.
|
|
435
|
+
*/
|
|
436
|
+
export class WotsKeyManager {
|
|
437
|
+
private storage: Map<string, WotsKeyState>
|
|
438
|
+
private persistFn?: (states: Map<string, WotsKeyState>) => Promise<void>
|
|
439
|
+
|
|
440
|
+
constructor(options: {
|
|
441
|
+
persistFn?: (states: Map<string, WotsKeyState>) => Promise<void>
|
|
442
|
+
initialStates?: Map<string, WotsKeyState>
|
|
443
|
+
} = {}) {
|
|
444
|
+
this.storage = options.initialStates ?? new Map()
|
|
445
|
+
this.persistFn = options.persistFn
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Register a new keypair
|
|
450
|
+
*/
|
|
451
|
+
async register(keypair: WinternitzKeypair): Promise<void> {
|
|
452
|
+
const key = bytesToHex(keypair.merkleRoot)
|
|
453
|
+
|
|
454
|
+
if (this.storage.has(key)) {
|
|
455
|
+
throw new Error(`Key ${key.slice(0, 16)} already registered`)
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
this.storage.set(key, {
|
|
459
|
+
merkleRoot: key,
|
|
460
|
+
used: false,
|
|
461
|
+
createdAt: Date.now(),
|
|
462
|
+
})
|
|
463
|
+
|
|
464
|
+
await this.persist()
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Check if a key can be used
|
|
469
|
+
*/
|
|
470
|
+
canUse(merkleRoot: Uint8Array): boolean {
|
|
471
|
+
const key = bytesToHex(merkleRoot)
|
|
472
|
+
const state = this.storage.get(key)
|
|
473
|
+
return state !== undefined && !state.used
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* Mark a key as used (MUST be called before signing)
|
|
478
|
+
*/
|
|
479
|
+
async markUsed(
|
|
480
|
+
merkleRoot: Uint8Array,
|
|
481
|
+
usedFor: string
|
|
482
|
+
): Promise<void> {
|
|
483
|
+
const key = bytesToHex(merkleRoot)
|
|
484
|
+
const state = this.storage.get(key)
|
|
485
|
+
|
|
486
|
+
if (!state) {
|
|
487
|
+
throw new Error(`Key ${key.slice(0, 16)} not registered`)
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
if (state.used) {
|
|
491
|
+
throw new Error(
|
|
492
|
+
`CRITICAL: Key ${key.slice(0, 16)} already used at ${state.usedAt}. ` +
|
|
493
|
+
`Reuse would compromise quantum security!`
|
|
494
|
+
)
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
state.used = true
|
|
498
|
+
state.usedAt = Date.now()
|
|
499
|
+
state.usedFor = usedFor
|
|
500
|
+
|
|
501
|
+
await this.persist()
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Get key state
|
|
506
|
+
*/
|
|
507
|
+
getState(merkleRoot: Uint8Array): WotsKeyState | undefined {
|
|
508
|
+
return this.storage.get(bytesToHex(merkleRoot))
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* List all keys
|
|
513
|
+
*/
|
|
514
|
+
listKeys(): WotsKeyState[] {
|
|
515
|
+
return Array.from(this.storage.values())
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
private async persist(): Promise<void> {
|
|
519
|
+
if (this.persistFn) {
|
|
520
|
+
await this.persistFn(this.storage)
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// ─── Utilities ────────────────────────────────────────────────────────────────
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Serialize keypair for storage
|
|
529
|
+
*/
|
|
530
|
+
export function serializeKeypair(keypair: WinternitzKeypair): {
|
|
531
|
+
privateKey: string
|
|
532
|
+
publicKey: string
|
|
533
|
+
merkleRoot: string
|
|
534
|
+
id: string
|
|
535
|
+
} {
|
|
536
|
+
return {
|
|
537
|
+
privateKey: bytesToHex(keypair.privateKey),
|
|
538
|
+
publicKey: bytesToHex(keypair.publicKey),
|
|
539
|
+
merkleRoot: bytesToHex(keypair.merkleRoot),
|
|
540
|
+
id: keypair.id,
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* Deserialize keypair from storage
|
|
546
|
+
*/
|
|
547
|
+
export function deserializeKeypair(data: {
|
|
548
|
+
privateKey: string
|
|
549
|
+
publicKey: string
|
|
550
|
+
merkleRoot: string
|
|
551
|
+
id: string
|
|
552
|
+
}): WinternitzKeypair {
|
|
553
|
+
return {
|
|
554
|
+
privateKey: hexToBytes(data.privateKey),
|
|
555
|
+
publicKey: hexToBytes(data.publicKey),
|
|
556
|
+
merkleRoot: hexToBytes(data.merkleRoot),
|
|
557
|
+
id: data.id,
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* Serialize signature for transmission
|
|
563
|
+
*/
|
|
564
|
+
export function serializeSignature(signature: WotsSignature): {
|
|
565
|
+
chains: string
|
|
566
|
+
messageHash: string
|
|
567
|
+
} {
|
|
568
|
+
return {
|
|
569
|
+
chains: bytesToHex(signature.chains),
|
|
570
|
+
messageHash: bytesToHex(signature.messageHash),
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* Deserialize signature
|
|
576
|
+
*/
|
|
577
|
+
export function deserializeSignature(data: {
|
|
578
|
+
chains: string
|
|
579
|
+
messageHash: string
|
|
580
|
+
}): WotsSignature {
|
|
581
|
+
return {
|
|
582
|
+
chains: hexToBytes(data.chains),
|
|
583
|
+
messageHash: hexToBytes(data.messageHash),
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// ─── Internal Helpers ─────────────────────────────────────────────────────────
|
|
588
|
+
|
|
589
|
+
function bytesToHex(bytes: Uint8Array): string {
|
|
590
|
+
return Array.from(bytes)
|
|
591
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
592
|
+
.join('')
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
function hexToBytes(hex: string): Uint8Array {
|
|
596
|
+
const cleaned = hex.startsWith('0x') ? hex.slice(2) : hex
|
|
597
|
+
const bytes = new Uint8Array(cleaned.length / 2)
|
|
598
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
599
|
+
bytes[i] = parseInt(cleaned.slice(i * 2, i * 2 + 2), 16)
|
|
600
|
+
}
|
|
601
|
+
return bytes
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
function constantTimeEqual(a: Uint8Array, b: Uint8Array): boolean {
|
|
605
|
+
if (a.length !== b.length) return false
|
|
606
|
+
let diff = 0
|
|
607
|
+
for (let i = 0; i < a.length; i++) {
|
|
608
|
+
diff |= a[i] ^ b[i]
|
|
609
|
+
}
|
|
610
|
+
return diff === 0
|
|
611
|
+
}
|
|
@@ -118,6 +118,7 @@ const DEFAULT_GAS_FEES: Record<ChainId, bigint> = {
|
|
|
118
118
|
celestia: 5000n, // 0.005 TIA in utia
|
|
119
119
|
sei: 5000n, // 0.005 SEI in usei
|
|
120
120
|
dydx: 5000n, // 0.000005 DYDX in dydx (18 decimals)
|
|
121
|
+
bsc: 21000n * 5n * 1000000000n, // 21k gas * 5 gwei = 0.000105 BNB
|
|
121
122
|
}
|
|
122
123
|
|
|
123
124
|
/**
|
package/src/settlement/index.ts
CHANGED
|
@@ -37,6 +37,15 @@ export {
|
|
|
37
37
|
type FindBestRouteParams,
|
|
38
38
|
} from './router'
|
|
39
39
|
|
|
40
|
+
// Circuit Breaker
|
|
41
|
+
export {
|
|
42
|
+
CircuitBreaker,
|
|
43
|
+
type CircuitState,
|
|
44
|
+
type CircuitBreakerStatus,
|
|
45
|
+
type CircuitBreakerEvents,
|
|
46
|
+
type CircuitBreakerOptions,
|
|
47
|
+
} from './router'
|
|
48
|
+
|
|
40
49
|
// Backends
|
|
41
50
|
export {
|
|
42
51
|
NEARIntentsBackend,
|