@sip-protocol/sdk 0.3.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/browser.d.mts +2 -2
  2. package/dist/browser.d.ts +2 -2
  3. package/dist/browser.js +2881 -295
  4. package/dist/browser.mjs +62 -2
  5. package/dist/chunk-AOZIY3GU.mjs +12995 -0
  6. package/dist/chunk-BCLIX5T2.mjs +12940 -0
  7. package/dist/chunk-DMHBKRWV.mjs +14712 -0
  8. package/dist/chunk-FKXPHKYD.mjs +12955 -0
  9. package/dist/chunk-HGU6HZRC.mjs +231 -0
  10. package/dist/chunk-J4Q4NJ2U.mjs +13544 -0
  11. package/dist/chunk-OPQ2GQIO.mjs +13013 -0
  12. package/dist/chunk-W2B7T6WU.mjs +14714 -0
  13. package/dist/index-5jAdWMA-.d.ts +8973 -0
  14. package/dist/index-B9Vkpaao.d.mts +8973 -0
  15. package/dist/index-BcWNakUD.d.ts +7990 -0
  16. package/dist/index-BsKY3Hr0.d.mts +7990 -0
  17. package/dist/index.d.mts +2 -2
  18. package/dist/index.d.ts +2 -2
  19. package/dist/index.js +2852 -266
  20. package/dist/index.mjs +62 -2
  21. package/dist/proofs/noir.mjs +1 -1
  22. package/package.json +2 -1
  23. package/src/adapters/near-intents.ts +8 -0
  24. package/src/bitcoin/index.ts +51 -0
  25. package/src/bitcoin/silent-payments.ts +865 -0
  26. package/src/bitcoin/taproot.ts +590 -0
  27. package/src/compliance/compliance-manager.ts +87 -0
  28. package/src/compliance/conditional-threshold.ts +379 -0
  29. package/src/compliance/conditional.ts +382 -0
  30. package/src/compliance/derivation.ts +489 -0
  31. package/src/compliance/index.ts +50 -8
  32. package/src/compliance/pdf.ts +365 -0
  33. package/src/compliance/reports.ts +644 -0
  34. package/src/compliance/threshold.ts +529 -0
  35. package/src/compliance/types.ts +223 -0
  36. package/src/cosmos/ibc-stealth.ts +825 -0
  37. package/src/cosmos/index.ts +83 -0
  38. package/src/cosmos/stealth.ts +487 -0
  39. package/src/errors.ts +8 -0
  40. package/src/index.ts +80 -1
  41. package/src/move/aptos.ts +369 -0
  42. package/src/move/index.ts +35 -0
  43. package/src/move/sui.ts +367 -0
  44. package/src/oracle/types.ts +8 -0
  45. package/src/settlement/backends/direct-chain.ts +8 -0
  46. package/src/stealth.ts +3 -3
  47. package/src/validation.ts +42 -1
  48. package/src/wallet/aptos/adapter.ts +422 -0
  49. package/src/wallet/aptos/index.ts +10 -0
  50. package/src/wallet/aptos/mock.ts +410 -0
  51. package/src/wallet/aptos/types.ts +278 -0
  52. package/src/wallet/bitcoin/adapter.ts +470 -0
  53. package/src/wallet/bitcoin/index.ts +38 -0
  54. package/src/wallet/bitcoin/mock.ts +516 -0
  55. package/src/wallet/bitcoin/types.ts +274 -0
  56. package/src/wallet/cosmos/adapter.ts +484 -0
  57. package/src/wallet/cosmos/index.ts +63 -0
  58. package/src/wallet/cosmos/mock.ts +596 -0
  59. package/src/wallet/cosmos/types.ts +462 -0
  60. package/src/wallet/index.ts +127 -0
  61. package/src/wallet/sui/adapter.ts +471 -0
  62. package/src/wallet/sui/index.ts +10 -0
  63. package/src/wallet/sui/mock.ts +439 -0
  64. package/src/wallet/sui/types.ts +245 -0
@@ -0,0 +1,382 @@
1
+ /**
2
+ * Conditional Disclosure Module for SIP Protocol
3
+ *
4
+ * Provides time-locked and block-height-locked disclosure mechanisms
5
+ * for regulatory compliance and automatic auditability.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { ConditionalDisclosure } from '@sip-protocol/sdk'
10
+ *
11
+ * const disclosure = new ConditionalDisclosure()
12
+ *
13
+ * // Create time-locked disclosure (reveals after 30 days)
14
+ * const timeLock = disclosure.createTimeLocked({
15
+ * viewingKey: '0x1234...',
16
+ * revealAfter: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),
17
+ * commitment: '0xabcd...',
18
+ * })
19
+ *
20
+ * // Check if unlocked (after time has passed)
21
+ * const result = disclosure.checkUnlocked(timeLock)
22
+ * if (result.unlocked) {
23
+ * console.log('Viewing key:', result.viewingKey)
24
+ * }
25
+ * ```
26
+ *
27
+ * @module compliance/conditional
28
+ */
29
+
30
+ import { sha256 } from '@noble/hashes/sha256'
31
+ import { bytesToHex, hexToBytes, randomBytes, utf8ToBytes } from '@noble/hashes/utils'
32
+ import { xchacha20poly1305 } from '@noble/ciphers/chacha.js'
33
+ import type { HexString } from '@sip-protocol/types'
34
+ import { ValidationError, CryptoError, ErrorCode } from '../errors'
35
+
36
+ /**
37
+ * Time-lock result containing encrypted viewing key and metadata
38
+ */
39
+ export interface TimeLockResult {
40
+ /** Encrypted viewing key */
41
+ encryptedKey: HexString
42
+ /** Nonce for XChaCha20-Poly1305 */
43
+ nonce: HexString
44
+ /** Reveal time (Unix timestamp in seconds) or block height */
45
+ revealAfter: number
46
+ /** Commitment to verify integrity (hash of viewingKey + revealAfter) */
47
+ verificationCommitment: HexString
48
+ /** Original commitment parameter (transaction hash or identifier) */
49
+ encryptionCommitment: HexString
50
+ /** Type of time-lock: 'timestamp' or 'blockheight' */
51
+ type: 'timestamp' | 'blockheight'
52
+ }
53
+
54
+ /**
55
+ * Unlock result from checking a time-locked disclosure
56
+ */
57
+ export interface UnlockResult {
58
+ /** Whether the time-lock is unlocked */
59
+ unlocked: boolean
60
+ /** Viewing key (only present if unlocked) */
61
+ viewingKey?: HexString
62
+ }
63
+
64
+ /**
65
+ * Parameters for creating a time-locked disclosure
66
+ */
67
+ export interface TimeLockParams {
68
+ /** Viewing key to encrypt and time-lock */
69
+ viewingKey: HexString
70
+ /** Reveal after this time (Date) or block height (number) */
71
+ revealAfter: Date | number
72
+ /** Commitment value (transaction hash or identifier) */
73
+ commitment: HexString
74
+ }
75
+
76
+ /**
77
+ * Conditional Disclosure Manager
78
+ *
79
+ * Handles automatic disclosure of viewing keys after specified
80
+ * time or block height for regulatory compliance.
81
+ */
82
+ export class ConditionalDisclosure {
83
+ /**
84
+ * Create a time-locked disclosure
85
+ *
86
+ * Encrypts the viewing key with a deterministic key derived from
87
+ * the commitment and reveal time. The key can only be reconstructed
88
+ * after the specified time/block height.
89
+ *
90
+ * @param params - Time-lock parameters
91
+ * @returns Time-lock result with encrypted key
92
+ * @throws {ValidationError} If parameters are invalid
93
+ * @throws {CryptoError} If encryption fails
94
+ */
95
+ createTimeLocked(params: TimeLockParams): TimeLockResult {
96
+ // Validate viewing key
97
+ if (!params.viewingKey || !params.viewingKey.startsWith('0x')) {
98
+ throw new ValidationError(
99
+ 'Invalid viewing key format',
100
+ 'viewingKey',
101
+ { viewingKey: params.viewingKey },
102
+ ErrorCode.INVALID_KEY
103
+ )
104
+ }
105
+
106
+ // Validate commitment
107
+ if (!params.commitment || !params.commitment.startsWith('0x')) {
108
+ throw new ValidationError(
109
+ 'Invalid commitment format',
110
+ 'commitment',
111
+ { commitment: params.commitment },
112
+ ErrorCode.INVALID_COMMITMENT
113
+ )
114
+ }
115
+
116
+ // Parse and validate revealAfter
117
+ let revealAfterSeconds: number
118
+ let type: 'timestamp' | 'blockheight'
119
+
120
+ if (params.revealAfter instanceof Date) {
121
+ revealAfterSeconds = Math.floor(params.revealAfter.getTime() / 1000)
122
+ type = 'timestamp'
123
+
124
+ // Note: We don't validate that the time is in the future to allow testing
125
+ // In production, applications should validate this before creating time-locks
126
+ } else if (typeof params.revealAfter === 'number') {
127
+ // Assume block height if number > 1e10, otherwise treat as timestamp
128
+ if (params.revealAfter > 1e10) {
129
+ // Looks like a timestamp in milliseconds, convert to seconds
130
+ revealAfterSeconds = Math.floor(params.revealAfter / 1000)
131
+ type = 'timestamp'
132
+ } else {
133
+ // Block height
134
+ revealAfterSeconds = params.revealAfter
135
+ type = 'blockheight'
136
+ }
137
+
138
+ if (revealAfterSeconds <= 0) {
139
+ throw new ValidationError(
140
+ 'Reveal time/block height must be positive',
141
+ 'revealAfter',
142
+ { revealAfter: revealAfterSeconds },
143
+ ErrorCode.INVALID_TIME_LOCK
144
+ )
145
+ }
146
+ } else {
147
+ throw new ValidationError(
148
+ 'Invalid revealAfter type (must be Date or number)',
149
+ 'revealAfter',
150
+ { revealAfter: params.revealAfter },
151
+ ErrorCode.INVALID_TIME_LOCK
152
+ )
153
+ }
154
+
155
+ try {
156
+ // Derive deterministic encryption key from commitment and reveal time
157
+ const encryptionKey = this._deriveEncryptionKey(
158
+ params.commitment,
159
+ revealAfterSeconds
160
+ )
161
+
162
+ // Generate random nonce (24 bytes for XChaCha20)
163
+ const nonce = randomBytes(24)
164
+
165
+ // Encrypt viewing key
166
+ const viewingKeyBytes = hexToBytes(params.viewingKey.slice(2))
167
+ const cipher = xchacha20poly1305(encryptionKey, nonce)
168
+ const encryptedKey = cipher.encrypt(viewingKeyBytes)
169
+
170
+ // Create verifiable commitment (hash of viewingKey + revealAfter)
171
+ const commitmentData = new Uint8Array([
172
+ ...viewingKeyBytes,
173
+ ...this._numberToBytes(revealAfterSeconds),
174
+ ])
175
+ const commitmentHash = sha256(commitmentData)
176
+
177
+ return {
178
+ encryptedKey: ('0x' + bytesToHex(encryptedKey)) as HexString,
179
+ nonce: ('0x' + bytesToHex(nonce)) as HexString,
180
+ revealAfter: revealAfterSeconds,
181
+ verificationCommitment: ('0x' + bytesToHex(commitmentHash)) as HexString,
182
+ encryptionCommitment: params.commitment,
183
+ type,
184
+ }
185
+ } catch (error) {
186
+ if (error instanceof ValidationError) {
187
+ throw error
188
+ }
189
+ throw new CryptoError(
190
+ 'Failed to create time-locked disclosure',
191
+ ErrorCode.ENCRYPTION_FAILED,
192
+ {
193
+ cause: error instanceof Error ? error : undefined,
194
+ operation: 'createTimeLocked',
195
+ }
196
+ )
197
+ }
198
+ }
199
+
200
+ /**
201
+ * Check if a time-lock is unlocked and retrieve the viewing key
202
+ *
203
+ * @param timeLock - Time-lock result to check
204
+ * @param currentTimeOrBlock - Current time (Date/number) or block height (number)
205
+ * @returns Unlock result with viewing key if unlocked
206
+ * @throws {ValidationError} If time-lock format is invalid
207
+ * @throws {CryptoError} If decryption fails
208
+ */
209
+ checkUnlocked(
210
+ timeLock: TimeLockResult,
211
+ currentTimeOrBlock?: Date | number
212
+ ): UnlockResult {
213
+ // Validate time-lock format
214
+ if (!timeLock.encryptedKey || !timeLock.encryptedKey.startsWith('0x')) {
215
+ throw new ValidationError(
216
+ 'Invalid encrypted key format',
217
+ 'encryptedKey',
218
+ { encryptedKey: timeLock.encryptedKey },
219
+ ErrorCode.INVALID_ENCRYPTED_DATA
220
+ )
221
+ }
222
+
223
+ if (!timeLock.nonce || !timeLock.nonce.startsWith('0x')) {
224
+ throw new ValidationError(
225
+ 'Invalid nonce format',
226
+ 'nonce',
227
+ { nonce: timeLock.nonce },
228
+ ErrorCode.INVALID_ENCRYPTED_DATA
229
+ )
230
+ }
231
+
232
+ if (!timeLock.verificationCommitment || !timeLock.verificationCommitment.startsWith('0x')) {
233
+ throw new ValidationError(
234
+ 'Invalid verification commitment format',
235
+ 'verificationCommitment',
236
+ { commitment: timeLock.verificationCommitment },
237
+ ErrorCode.INVALID_COMMITMENT
238
+ )
239
+ }
240
+
241
+ if (!timeLock.encryptionCommitment || !timeLock.encryptionCommitment.startsWith('0x')) {
242
+ throw new ValidationError(
243
+ 'Invalid encryption commitment format',
244
+ 'encryptionCommitment',
245
+ { commitment: timeLock.encryptionCommitment },
246
+ ErrorCode.INVALID_COMMITMENT
247
+ )
248
+ }
249
+
250
+ // Determine current time or block height
251
+ let currentValue: number
252
+ if (currentTimeOrBlock instanceof Date) {
253
+ currentValue = Math.floor(currentTimeOrBlock.getTime() / 1000)
254
+ } else if (typeof currentTimeOrBlock === 'number') {
255
+ currentValue = currentTimeOrBlock
256
+ } else {
257
+ // Default to current time
258
+ currentValue = Math.floor(Date.now() / 1000)
259
+ }
260
+
261
+ // Check if unlocked
262
+ const unlocked = currentValue >= timeLock.revealAfter
263
+
264
+ if (!unlocked) {
265
+ return { unlocked: false }
266
+ }
267
+
268
+ try {
269
+ // Derive the encryption key using the stored commitment
270
+ const encryptionKey = this._deriveEncryptionKey(
271
+ timeLock.encryptionCommitment,
272
+ timeLock.revealAfter
273
+ )
274
+
275
+ // Decrypt the viewing key
276
+ const nonce = hexToBytes(timeLock.nonce.slice(2))
277
+ const encryptedData = hexToBytes(timeLock.encryptedKey.slice(2))
278
+
279
+ const cipher = xchacha20poly1305(encryptionKey, nonce)
280
+ const decryptedBytes = cipher.decrypt(encryptedData)
281
+
282
+ const viewingKey = ('0x' + bytesToHex(decryptedBytes)) as HexString
283
+
284
+ return {
285
+ unlocked: true,
286
+ viewingKey,
287
+ }
288
+ } catch (error) {
289
+ if (error instanceof ValidationError || error instanceof CryptoError) {
290
+ throw error
291
+ }
292
+ throw new CryptoError(
293
+ 'Failed to decrypt time-locked viewing key',
294
+ ErrorCode.DECRYPTION_FAILED,
295
+ {
296
+ cause: error instanceof Error ? error : undefined,
297
+ operation: 'checkUnlocked',
298
+ }
299
+ )
300
+ }
301
+ }
302
+
303
+ /**
304
+ * Verify a time-lock commitment
305
+ *
306
+ * Verifies that the verification commitment in the time-lock matches the hash
307
+ * of the provided viewing key and reveal time.
308
+ *
309
+ * @param timeLock - Time-lock to verify
310
+ * @param viewingKey - Viewing key to verify against
311
+ * @returns True if commitment is valid
312
+ */
313
+ verifyCommitment(timeLock: TimeLockResult, viewingKey: HexString): boolean {
314
+ try {
315
+ const viewingKeyBytes = hexToBytes(viewingKey.slice(2))
316
+ const commitmentData = new Uint8Array([
317
+ ...viewingKeyBytes,
318
+ ...this._numberToBytes(timeLock.revealAfter),
319
+ ])
320
+ const expectedCommitment = sha256(commitmentData)
321
+ const actualCommitment = hexToBytes(timeLock.verificationCommitment.slice(2))
322
+
323
+ // Constant-time comparison
324
+ if (expectedCommitment.length !== actualCommitment.length) {
325
+ return false
326
+ }
327
+
328
+ let diff = 0
329
+ for (let i = 0; i < expectedCommitment.length; i++) {
330
+ diff |= expectedCommitment[i] ^ actualCommitment[i]
331
+ }
332
+
333
+ return diff === 0
334
+ } catch {
335
+ return false
336
+ }
337
+ }
338
+
339
+ /**
340
+ * Derive deterministic encryption key from commitment and reveal time
341
+ *
342
+ * @private
343
+ */
344
+ private _deriveEncryptionKey(
345
+ commitment: HexString,
346
+ revealAfter: number
347
+ ): Uint8Array {
348
+ // Combine commitment and reveal time
349
+ const commitmentBytes = hexToBytes(commitment.slice(2))
350
+ const timeBytes = this._numberToBytes(revealAfter)
351
+ const combined = new Uint8Array([...commitmentBytes, ...timeBytes])
352
+
353
+ // Hash to derive key (32 bytes for XChaCha20-Poly1305)
354
+ const key = sha256(combined)
355
+
356
+ if (key.length !== 32) {
357
+ throw new CryptoError(
358
+ 'Derived key must be 32 bytes',
359
+ ErrorCode.INVALID_KEY_SIZE,
360
+ {
361
+ context: { actualSize: key.length, expectedSize: 32 },
362
+ operation: '_deriveEncryptionKey',
363
+ }
364
+ )
365
+ }
366
+
367
+ return key
368
+ }
369
+
370
+ /**
371
+ * Convert number to 8-byte big-endian representation
372
+ *
373
+ * @private
374
+ */
375
+ private _numberToBytes(num: number): Uint8Array {
376
+ const bytes = new Uint8Array(8)
377
+ const view = new DataView(bytes.buffer)
378
+ // Use BigInt to handle large numbers safely
379
+ view.setBigUint64(0, BigInt(Math.floor(num)), false) // false = big-endian
380
+ return bytes
381
+ }
382
+ }