@sip-protocol/sdk 0.2.8 → 0.2.10
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 +349 -0
- package/dist/browser.d.mts +100 -2
- package/dist/browser.d.ts +100 -2
- package/dist/browser.js +1362 -268
- package/dist/browser.mjs +502 -16
- package/dist/{chunk-UPTISVCY.mjs → chunk-AV37IZST.mjs} +731 -15
- package/dist/{chunk-VITVG25F.mjs → chunk-XLEPIR2P.mjs} +2 -100
- package/dist/index-BFOKTz2z.d.ts +6062 -0
- package/dist/index-CAhjA4kh.d.mts +6062 -0
- package/dist/index.d.mts +2 -5609
- package/dist/index.d.ts +2 -5609
- package/dist/index.js +588 -154
- package/dist/index.mjs +5 -1
- package/dist/{noir-BHQtFvRk.d.mts → noir-BTyLXLlZ.d.mts} +1 -1
- package/dist/{noir-BHQtFvRk.d.ts → noir-BTyLXLlZ.d.ts} +1 -1
- package/dist/proofs/noir.d.mts +1 -1
- package/dist/proofs/noir.d.ts +1 -1
- package/dist/proofs/noir.js +11 -112
- package/dist/proofs/noir.mjs +10 -13
- package/package.json +16 -16
- package/src/browser.ts +23 -0
- package/src/index.ts +12 -0
- package/src/proofs/browser-utils.ts +389 -0
- package/src/proofs/browser.ts +246 -19
- package/src/proofs/circuits/funding_proof.json +1 -1
- package/src/proofs/noir.ts +14 -14
- package/src/proofs/worker.ts +426 -0
- package/src/zcash/bridge.ts +738 -0
- package/src/zcash/index.ts +36 -1
- package/src/zcash/swap-service.ts +793 -0
- package/dist/chunk-4VJHI66K.mjs +0 -12120
- package/dist/chunk-5BAS4D44.mjs +0 -10283
- package/dist/chunk-6WOV2YNG.mjs +0 -10179
- package/dist/chunk-DU7LQDD2.mjs +0 -10148
- package/dist/chunk-MR7HRCRS.mjs +0 -10165
- package/dist/chunk-NDGUWOOZ.mjs +0 -10157
- package/dist/chunk-O4Y2ZUDL.mjs +0 -12721
- package/dist/chunk-VXSHK7US.mjs +0 -10158
package/dist/browser.mjs
CHANGED
|
@@ -47,6 +47,7 @@ import {
|
|
|
47
47
|
ZcashRPCClient,
|
|
48
48
|
ZcashRPCError,
|
|
49
49
|
ZcashShieldedService,
|
|
50
|
+
ZcashSwapService,
|
|
50
51
|
addBlindings,
|
|
51
52
|
addCommitments,
|
|
52
53
|
addOracle,
|
|
@@ -54,6 +55,7 @@ import {
|
|
|
54
55
|
base58ToHex,
|
|
55
56
|
bytesToHex,
|
|
56
57
|
checkEd25519StealthAddress,
|
|
58
|
+
checkMobileWASMCompatibility,
|
|
57
59
|
checkStealthAddress,
|
|
58
60
|
commit,
|
|
59
61
|
commitZero,
|
|
@@ -80,6 +82,7 @@ import {
|
|
|
80
82
|
createWalletFactory,
|
|
81
83
|
createZcashClient,
|
|
82
84
|
createZcashShieldedService,
|
|
85
|
+
createZcashSwapService,
|
|
83
86
|
decodeStealthMetaAddress,
|
|
84
87
|
decryptMemo,
|
|
85
88
|
decryptWithViewing,
|
|
@@ -91,6 +94,8 @@ import {
|
|
|
91
94
|
deserializeIntent,
|
|
92
95
|
deserializePayment,
|
|
93
96
|
detectEthereumWallets,
|
|
97
|
+
detectMobileBrowser,
|
|
98
|
+
detectMobilePlatform,
|
|
94
99
|
detectSolanaWallets,
|
|
95
100
|
ed25519PublicKeyToNearAddress,
|
|
96
101
|
ed25519PublicKeyToSolanaAddress,
|
|
@@ -111,6 +116,7 @@ import {
|
|
|
111
116
|
getActiveOracles,
|
|
112
117
|
getAvailableTransports,
|
|
113
118
|
getBrowserInfo,
|
|
119
|
+
getBrowserVersion,
|
|
114
120
|
getChainNumericId,
|
|
115
121
|
getChainsForStablecoin,
|
|
116
122
|
getCurveForChain,
|
|
@@ -119,6 +125,8 @@ import {
|
|
|
119
125
|
getEthereumProvider,
|
|
120
126
|
getGenerators,
|
|
121
127
|
getIntentSummary,
|
|
128
|
+
getMobileDeviceInfo,
|
|
129
|
+
getOSVersion,
|
|
122
130
|
getPaymentSummary,
|
|
123
131
|
getPaymentTimeRemaining,
|
|
124
132
|
getPrivacyConfig,
|
|
@@ -143,6 +151,7 @@ import {
|
|
|
143
151
|
isPrivateWalletAdapter,
|
|
144
152
|
isStablecoin,
|
|
145
153
|
isStablecoinOnChain,
|
|
154
|
+
isTablet,
|
|
146
155
|
isValidAmount,
|
|
147
156
|
isValidChainId,
|
|
148
157
|
isValidCompressedPublicKey,
|
|
@@ -174,7 +183,10 @@ import {
|
|
|
174
183
|
subtractBlindings,
|
|
175
184
|
subtractCommitments,
|
|
176
185
|
supportsSharedArrayBuffer,
|
|
186
|
+
supportsTouch,
|
|
177
187
|
supportsViewingKey,
|
|
188
|
+
supportsWASMBulkMemory,
|
|
189
|
+
supportsWASMSimd,
|
|
178
190
|
supportsWebBluetooth,
|
|
179
191
|
supportsWebHID,
|
|
180
192
|
supportsWebUSB,
|
|
@@ -197,12 +209,12 @@ import {
|
|
|
197
209
|
walletRegistry,
|
|
198
210
|
withSecureBuffer,
|
|
199
211
|
withSecureBufferSync
|
|
200
|
-
} from "./chunk-
|
|
212
|
+
} from "./chunk-AV37IZST.mjs";
|
|
201
213
|
import {
|
|
202
214
|
fulfillment_proof_default,
|
|
203
215
|
funding_proof_default,
|
|
204
216
|
validity_proof_default
|
|
205
|
-
} from "./chunk-
|
|
217
|
+
} from "./chunk-XLEPIR2P.mjs";
|
|
206
218
|
import {
|
|
207
219
|
CryptoError,
|
|
208
220
|
EncryptionNotImplementedError,
|
|
@@ -228,6 +240,9 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
228
240
|
framework = "noir";
|
|
229
241
|
_isReady = false;
|
|
230
242
|
config;
|
|
243
|
+
// Mobile device info (cached)
|
|
244
|
+
deviceInfo = null;
|
|
245
|
+
wasmCompatibility = null;
|
|
231
246
|
// Circuit instances
|
|
232
247
|
fundingNoir = null;
|
|
233
248
|
fundingBackend = null;
|
|
@@ -239,17 +254,25 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
239
254
|
worker = null;
|
|
240
255
|
workerPending = /* @__PURE__ */ new Map();
|
|
241
256
|
constructor(config = {}) {
|
|
257
|
+
this.deviceInfo = getMobileDeviceInfo();
|
|
258
|
+
const isMobile = this.deviceInfo.isMobile;
|
|
259
|
+
const defaultTimeout = isMobile ? 12e4 : 6e4;
|
|
242
260
|
this.config = {
|
|
243
261
|
useWorker: config.useWorker ?? true,
|
|
244
262
|
verbose: config.verbose ?? false,
|
|
245
263
|
oraclePublicKey: config.oraclePublicKey ?? void 0,
|
|
246
|
-
timeout: config.timeout ??
|
|
264
|
+
timeout: config.timeout ?? defaultTimeout,
|
|
265
|
+
mobileMode: config.mobileMode ?? isMobile,
|
|
266
|
+
forceInitialize: config.forceInitialize ?? false
|
|
247
267
|
};
|
|
248
268
|
if (!isBrowser()) {
|
|
249
269
|
console.warn(
|
|
250
270
|
"[BrowserNoirProvider] Not running in browser environment. Consider using NoirProofProvider for Node.js."
|
|
251
271
|
);
|
|
252
272
|
}
|
|
273
|
+
if (this.config.verbose && this.deviceInfo) {
|
|
274
|
+
console.log("[BrowserNoirProvider] Device info:", this.deviceInfo);
|
|
275
|
+
}
|
|
253
276
|
}
|
|
254
277
|
get isReady() {
|
|
255
278
|
return this._isReady;
|
|
@@ -279,6 +302,67 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
279
302
|
missing
|
|
280
303
|
};
|
|
281
304
|
}
|
|
305
|
+
/**
|
|
306
|
+
* Get detailed mobile device information
|
|
307
|
+
*/
|
|
308
|
+
static getMobileInfo() {
|
|
309
|
+
return getMobileDeviceInfo();
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Check mobile WASM compatibility
|
|
313
|
+
*
|
|
314
|
+
* Returns detailed compatibility information including:
|
|
315
|
+
* - Feature support (WASM, SharedArrayBuffer, Workers, SIMD)
|
|
316
|
+
* - Compatibility score (0-100)
|
|
317
|
+
* - Issues and recommendations
|
|
318
|
+
*
|
|
319
|
+
* @example
|
|
320
|
+
* ```typescript
|
|
321
|
+
* const compat = BrowserNoirProvider.checkMobileCompatibility()
|
|
322
|
+
* if (compat.score < 70) {
|
|
323
|
+
* console.warn('Limited mobile support:', compat.issues)
|
|
324
|
+
* }
|
|
325
|
+
* ```
|
|
326
|
+
*/
|
|
327
|
+
static checkMobileCompatibility() {
|
|
328
|
+
return checkMobileWASMCompatibility();
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Check if the current device is mobile
|
|
332
|
+
*/
|
|
333
|
+
static isMobile() {
|
|
334
|
+
return getMobileDeviceInfo().isMobile;
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Get recommended configuration for the current device
|
|
338
|
+
*
|
|
339
|
+
* Automatically adjusts settings based on device capabilities:
|
|
340
|
+
* - Mobile devices get longer timeouts
|
|
341
|
+
* - Low-memory devices disable workers
|
|
342
|
+
* - Tablets get intermediate settings
|
|
343
|
+
*/
|
|
344
|
+
static getRecommendedConfig() {
|
|
345
|
+
const deviceInfo = getMobileDeviceInfo();
|
|
346
|
+
const compat = checkMobileWASMCompatibility();
|
|
347
|
+
const config = {};
|
|
348
|
+
if (deviceInfo.isMobile) {
|
|
349
|
+
config.timeout = 12e4;
|
|
350
|
+
config.mobileMode = true;
|
|
351
|
+
if (deviceInfo.deviceMemoryGB !== null && deviceInfo.deviceMemoryGB < 2) {
|
|
352
|
+
config.useWorker = false;
|
|
353
|
+
}
|
|
354
|
+
if (deviceInfo.platform === "ios" && deviceInfo.browser === "safari") {
|
|
355
|
+
config.useWorker = compat.sharedArrayBuffer;
|
|
356
|
+
}
|
|
357
|
+
} else if (deviceInfo.isTablet) {
|
|
358
|
+
config.timeout = 9e4;
|
|
359
|
+
config.mobileMode = true;
|
|
360
|
+
}
|
|
361
|
+
if (compat.score < 50) {
|
|
362
|
+
config.forceInitialize = false;
|
|
363
|
+
}
|
|
364
|
+
return config;
|
|
365
|
+
}
|
|
282
366
|
/**
|
|
283
367
|
* Derive secp256k1 public key coordinates from a private key
|
|
284
368
|
*/
|
|
@@ -288,6 +372,18 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
288
372
|
const y = Array.from(uncompressedPubKey.slice(33, 65));
|
|
289
373
|
return { x, y };
|
|
290
374
|
}
|
|
375
|
+
/**
|
|
376
|
+
* Get the cached WASM compatibility info (available after construction)
|
|
377
|
+
*/
|
|
378
|
+
getWASMCompatibility() {
|
|
379
|
+
return this.wasmCompatibility;
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Get the cached device info (available after construction)
|
|
383
|
+
*/
|
|
384
|
+
getDeviceInfo() {
|
|
385
|
+
return this.deviceInfo;
|
|
386
|
+
}
|
|
291
387
|
/**
|
|
292
388
|
* Initialize the browser provider
|
|
293
389
|
*
|
|
@@ -300,8 +396,18 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
300
396
|
if (this._isReady) {
|
|
301
397
|
return;
|
|
302
398
|
}
|
|
399
|
+
this.wasmCompatibility = checkMobileWASMCompatibility();
|
|
400
|
+
if (this.config.verbose) {
|
|
401
|
+
console.log("[BrowserNoirProvider] WASM compatibility:", this.wasmCompatibility);
|
|
402
|
+
}
|
|
403
|
+
if (this.wasmCompatibility.score < 50 && !this.config.forceInitialize) {
|
|
404
|
+
throw new ProofError(
|
|
405
|
+
`Device has poor WASM compatibility (score: ${this.wasmCompatibility.score}). Issues: ${this.wasmCompatibility.issues.join(", ")}. Set forceInitialize: true to override.`,
|
|
406
|
+
"SIP_4004" /* PROOF_PROVIDER_NOT_READY */
|
|
407
|
+
);
|
|
408
|
+
}
|
|
303
409
|
const { supported, missing } = _BrowserNoirProvider.checkBrowserSupport();
|
|
304
|
-
if (!supported) {
|
|
410
|
+
if (!supported && !this.config.forceInitialize) {
|
|
305
411
|
throw new ProofError(
|
|
306
412
|
`Browser missing required features: ${missing.join(", ")}`,
|
|
307
413
|
"SIP_4004" /* PROOF_PROVIDER_NOT_READY */
|
|
@@ -365,8 +471,69 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
365
471
|
* Initialize Web Worker for off-main-thread proof generation
|
|
366
472
|
*/
|
|
367
473
|
async initializeWorker() {
|
|
368
|
-
if (
|
|
369
|
-
|
|
474
|
+
if (!supportsWebWorkers()) {
|
|
475
|
+
if (this.config.verbose) {
|
|
476
|
+
console.log("[BrowserNoirProvider] Web Workers not supported, using main thread");
|
|
477
|
+
}
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
try {
|
|
481
|
+
const workerCode = this.getWorkerCode();
|
|
482
|
+
const blob = new Blob([workerCode], { type: "application/javascript" });
|
|
483
|
+
const workerURL = URL.createObjectURL(blob);
|
|
484
|
+
this.worker = new Worker(workerURL, { type: "module" });
|
|
485
|
+
this.worker.onmessage = (event) => {
|
|
486
|
+
this.handleWorkerMessage(event.data);
|
|
487
|
+
};
|
|
488
|
+
this.worker.onerror = (error) => {
|
|
489
|
+
console.error("[BrowserNoirProvider] Worker error:", error);
|
|
490
|
+
for (const [id, { reject }] of this.workerPending) {
|
|
491
|
+
reject(new Error(`Worker error: ${error.message}`));
|
|
492
|
+
this.workerPending.delete(id);
|
|
493
|
+
}
|
|
494
|
+
this.worker?.terminate();
|
|
495
|
+
this.worker = null;
|
|
496
|
+
};
|
|
497
|
+
URL.revokeObjectURL(workerURL);
|
|
498
|
+
if (this.config.verbose) {
|
|
499
|
+
console.log("[BrowserNoirProvider] Web Worker initialized successfully");
|
|
500
|
+
}
|
|
501
|
+
} catch (error) {
|
|
502
|
+
if (this.config.verbose) {
|
|
503
|
+
console.warn("[BrowserNoirProvider] Failed to initialize worker, using main thread:", error);
|
|
504
|
+
}
|
|
505
|
+
this.worker = null;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Get inline worker code for bundler compatibility
|
|
510
|
+
*/
|
|
511
|
+
getWorkerCode() {
|
|
512
|
+
return `
|
|
513
|
+
self.onmessage = async function(event) {
|
|
514
|
+
const { id, type } = event.data;
|
|
515
|
+
// Signal that worker received message but proof gen happens on main thread
|
|
516
|
+
self.postMessage({ id, type: 'fallback', message: 'Worker initialized, using main thread for proofs' });
|
|
517
|
+
};
|
|
518
|
+
`;
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Handle messages from worker
|
|
522
|
+
*/
|
|
523
|
+
handleWorkerMessage(data) {
|
|
524
|
+
const pending = this.workerPending.get(data.id);
|
|
525
|
+
if (!pending) return;
|
|
526
|
+
switch (data.type) {
|
|
527
|
+
case "success":
|
|
528
|
+
this.workerPending.delete(data.id);
|
|
529
|
+
pending.resolve(data.result);
|
|
530
|
+
break;
|
|
531
|
+
case "error":
|
|
532
|
+
this.workerPending.delete(data.id);
|
|
533
|
+
pending.reject(new Error(data.error));
|
|
534
|
+
break;
|
|
535
|
+
case "fallback":
|
|
536
|
+
break;
|
|
370
537
|
}
|
|
371
538
|
}
|
|
372
539
|
/**
|
|
@@ -388,15 +555,10 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
388
555
|
percent: 10,
|
|
389
556
|
message: "Preparing witness inputs..."
|
|
390
557
|
});
|
|
391
|
-
const
|
|
392
|
-
params.balance,
|
|
393
|
-
params.blindingFactor,
|
|
394
|
-
params.assetId
|
|
395
|
-
);
|
|
558
|
+
const blindingField = this.bytesToField(params.blindingFactor);
|
|
396
559
|
const witnessInputs = {
|
|
397
|
-
commitment_hash: commitmentHash,
|
|
398
560
|
minimum_required: params.minimumRequired.toString(),
|
|
399
|
-
asset_id: this.assetIdToField(params.assetId)
|
|
561
|
+
asset_id: `0x${this.assetIdToField(params.assetId)}`,
|
|
400
562
|
balance: params.balance.toString(),
|
|
401
563
|
blinding: blindingField
|
|
402
564
|
};
|
|
@@ -405,7 +567,7 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
405
567
|
percent: 30,
|
|
406
568
|
message: "Generating witness..."
|
|
407
569
|
});
|
|
408
|
-
const { witness } = await this.fundingNoir.execute(witnessInputs);
|
|
570
|
+
const { witness, returnValue } = await this.fundingNoir.execute(witnessInputs);
|
|
409
571
|
onProgress?.({
|
|
410
572
|
stage: "proving",
|
|
411
573
|
percent: 50,
|
|
@@ -417,10 +579,12 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
417
579
|
percent: 100,
|
|
418
580
|
message: "Proof generated successfully"
|
|
419
581
|
});
|
|
582
|
+
const commitmentHashBytes = returnValue;
|
|
583
|
+
const commitmentHashHex = bytesToHex(new Uint8Array(commitmentHashBytes));
|
|
420
584
|
const publicInputs = [
|
|
421
|
-
`0x${commitmentHash}`,
|
|
422
585
|
`0x${params.minimumRequired.toString(16).padStart(16, "0")}`,
|
|
423
|
-
`0x${this.assetIdToField(params.assetId)}
|
|
586
|
+
`0x${this.assetIdToField(params.assetId)}`,
|
|
587
|
+
`0x${commitmentHashHex}`
|
|
424
588
|
];
|
|
425
589
|
const proof = {
|
|
426
590
|
type: "funding",
|
|
@@ -822,6 +986,314 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
822
986
|
return { x, y };
|
|
823
987
|
}
|
|
824
988
|
};
|
|
989
|
+
|
|
990
|
+
// src/proofs/worker.ts
|
|
991
|
+
function createWorkerBlobURL() {
|
|
992
|
+
const workerCode = `
|
|
993
|
+
// Proof Generation Worker
|
|
994
|
+
// This code runs in a separate thread
|
|
995
|
+
|
|
996
|
+
let fundingNoir = null;
|
|
997
|
+
let fundingBackend = null;
|
|
998
|
+
let validityNoir = null;
|
|
999
|
+
let validityBackend = null;
|
|
1000
|
+
let fulfillmentNoir = null;
|
|
1001
|
+
let fulfillmentBackend = null;
|
|
1002
|
+
let isReady = false;
|
|
1003
|
+
let config = { verbose: false };
|
|
1004
|
+
|
|
1005
|
+
// Helper to send progress updates
|
|
1006
|
+
function sendProgress(id, stage, percent, message) {
|
|
1007
|
+
self.postMessage({
|
|
1008
|
+
id,
|
|
1009
|
+
type: 'progress',
|
|
1010
|
+
progress: { stage, percent, message }
|
|
1011
|
+
});
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
// Helper to send error
|
|
1015
|
+
function sendError(id, error) {
|
|
1016
|
+
self.postMessage({
|
|
1017
|
+
id,
|
|
1018
|
+
type: 'error',
|
|
1019
|
+
error: error.message || String(error)
|
|
1020
|
+
});
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
// Helper to send success
|
|
1024
|
+
function sendSuccess(id, result) {
|
|
1025
|
+
self.postMessage({
|
|
1026
|
+
id,
|
|
1027
|
+
type: 'success',
|
|
1028
|
+
result
|
|
1029
|
+
});
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
// Initialize circuits (called once)
|
|
1033
|
+
async function initialize(id, initConfig) {
|
|
1034
|
+
try {
|
|
1035
|
+
sendProgress(id, 'initializing', 10, 'Loading Noir JS...');
|
|
1036
|
+
|
|
1037
|
+
// Dynamic imports for Noir
|
|
1038
|
+
const { Noir } = await import('@noir-lang/noir_js');
|
|
1039
|
+
const { UltraHonkBackend } = await import('@aztec/bb.js');
|
|
1040
|
+
|
|
1041
|
+
sendProgress(id, 'initializing', 30, 'Loading circuit artifacts...');
|
|
1042
|
+
|
|
1043
|
+
// Load circuit artifacts
|
|
1044
|
+
const [fundingArtifact, validityArtifact, fulfillmentArtifact] = await Promise.all([
|
|
1045
|
+
fetch(new URL('./circuits/funding_proof.json', import.meta.url)).then(r => r.json()),
|
|
1046
|
+
fetch(new URL('./circuits/validity_proof.json', import.meta.url)).then(r => r.json()),
|
|
1047
|
+
fetch(new URL('./circuits/fulfillment_proof.json', import.meta.url)).then(r => r.json()),
|
|
1048
|
+
]);
|
|
1049
|
+
|
|
1050
|
+
sendProgress(id, 'initializing', 50, 'Initializing backends...');
|
|
1051
|
+
|
|
1052
|
+
// Initialize Noir instances
|
|
1053
|
+
fundingNoir = new Noir(fundingArtifact);
|
|
1054
|
+
fundingBackend = new UltraHonkBackend(fundingArtifact.bytecode);
|
|
1055
|
+
|
|
1056
|
+
sendProgress(id, 'initializing', 70, 'Initializing validity circuit...');
|
|
1057
|
+
validityNoir = new Noir(validityArtifact);
|
|
1058
|
+
validityBackend = new UltraHonkBackend(validityArtifact.bytecode);
|
|
1059
|
+
|
|
1060
|
+
sendProgress(id, 'initializing', 90, 'Initializing fulfillment circuit...');
|
|
1061
|
+
fulfillmentNoir = new Noir(fulfillmentArtifact);
|
|
1062
|
+
fulfillmentBackend = new UltraHonkBackend(fulfillmentArtifact.bytecode);
|
|
1063
|
+
|
|
1064
|
+
config = initConfig || { verbose: false };
|
|
1065
|
+
isReady = true;
|
|
1066
|
+
|
|
1067
|
+
sendProgress(id, 'complete', 100, 'Worker initialized');
|
|
1068
|
+
sendSuccess(id, { initialized: true });
|
|
1069
|
+
} catch (error) {
|
|
1070
|
+
sendError(id, error);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
// Generate funding proof
|
|
1075
|
+
async function generateFundingProof(id, params) {
|
|
1076
|
+
if (!isReady) {
|
|
1077
|
+
sendError(id, new Error('Worker not initialized'));
|
|
1078
|
+
return;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
try {
|
|
1082
|
+
sendProgress(id, 'witness', 20, 'Preparing witness...');
|
|
1083
|
+
|
|
1084
|
+
// Convert blinding factor to field
|
|
1085
|
+
const blindingField = bytesToField(params.blindingFactor);
|
|
1086
|
+
|
|
1087
|
+
const witnessInputs = {
|
|
1088
|
+
minimum_required: params.minimumRequired.toString(),
|
|
1089
|
+
asset_id: '0x' + assetIdToField(params.assetId),
|
|
1090
|
+
balance: params.balance.toString(),
|
|
1091
|
+
blinding: blindingField,
|
|
1092
|
+
};
|
|
1093
|
+
|
|
1094
|
+
sendProgress(id, 'witness', 40, 'Executing circuit...');
|
|
1095
|
+
const { witness, returnValue } = await fundingNoir.execute(witnessInputs);
|
|
1096
|
+
|
|
1097
|
+
sendProgress(id, 'proving', 60, 'Generating proof...');
|
|
1098
|
+
const proofData = await fundingBackend.generateProof(witness);
|
|
1099
|
+
|
|
1100
|
+
sendProgress(id, 'complete', 100, 'Proof generated');
|
|
1101
|
+
|
|
1102
|
+
// Extract commitment hash from return value
|
|
1103
|
+
const commitmentHashHex = bytesToHex(new Uint8Array(returnValue));
|
|
1104
|
+
|
|
1105
|
+
const publicInputs = [
|
|
1106
|
+
'0x' + params.minimumRequired.toString(16).padStart(16, '0'),
|
|
1107
|
+
'0x' + assetIdToField(params.assetId),
|
|
1108
|
+
'0x' + commitmentHashHex,
|
|
1109
|
+
];
|
|
1110
|
+
|
|
1111
|
+
const proof = {
|
|
1112
|
+
type: 'funding',
|
|
1113
|
+
proof: '0x' + bytesToHex(proofData.proof),
|
|
1114
|
+
publicInputs,
|
|
1115
|
+
};
|
|
1116
|
+
|
|
1117
|
+
sendSuccess(id, { proof, publicInputs });
|
|
1118
|
+
} catch (error) {
|
|
1119
|
+
sendError(id, error);
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
// Helper functions
|
|
1124
|
+
function bytesToField(bytes) {
|
|
1125
|
+
let result = 0n;
|
|
1126
|
+
const len = Math.min(bytes.length, 31);
|
|
1127
|
+
for (let i = 0; i < len; i++) {
|
|
1128
|
+
result = result * 256n + BigInt(bytes[i]);
|
|
1129
|
+
}
|
|
1130
|
+
return result.toString();
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
function assetIdToField(assetId) {
|
|
1134
|
+
if (assetId.startsWith('0x')) {
|
|
1135
|
+
return assetId.slice(2).padStart(64, '0');
|
|
1136
|
+
}
|
|
1137
|
+
const encoder = new TextEncoder();
|
|
1138
|
+
const bytes = encoder.encode(assetId);
|
|
1139
|
+
let result = 0n;
|
|
1140
|
+
for (let i = 0; i < bytes.length && i < 31; i++) {
|
|
1141
|
+
result = result * 256n + BigInt(bytes[i]);
|
|
1142
|
+
}
|
|
1143
|
+
return result.toString(16).padStart(64, '0');
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
function bytesToHex(bytes) {
|
|
1147
|
+
return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
// Message handler
|
|
1151
|
+
self.onmessage = async function(event) {
|
|
1152
|
+
const { id, type, params, config: initConfig } = event.data;
|
|
1153
|
+
|
|
1154
|
+
switch (type) {
|
|
1155
|
+
case 'init':
|
|
1156
|
+
await initialize(id, initConfig);
|
|
1157
|
+
break;
|
|
1158
|
+
case 'generateFundingProof':
|
|
1159
|
+
await generateFundingProof(id, params);
|
|
1160
|
+
break;
|
|
1161
|
+
case 'generateValidityProof':
|
|
1162
|
+
// TODO: Implement
|
|
1163
|
+
sendError(id, new Error('Validity proof not yet implemented in worker'));
|
|
1164
|
+
break;
|
|
1165
|
+
case 'generateFulfillmentProof':
|
|
1166
|
+
// TODO: Implement
|
|
1167
|
+
sendError(id, new Error('Fulfillment proof not yet implemented in worker'));
|
|
1168
|
+
break;
|
|
1169
|
+
case 'destroy':
|
|
1170
|
+
// Cleanup
|
|
1171
|
+
fundingNoir = null;
|
|
1172
|
+
fundingBackend = null;
|
|
1173
|
+
validityNoir = null;
|
|
1174
|
+
validityBackend = null;
|
|
1175
|
+
fulfillmentNoir = null;
|
|
1176
|
+
fulfillmentBackend = null;
|
|
1177
|
+
isReady = false;
|
|
1178
|
+
sendSuccess(id, { destroyed: true });
|
|
1179
|
+
break;
|
|
1180
|
+
default:
|
|
1181
|
+
sendError(id, new Error('Unknown message type: ' + type));
|
|
1182
|
+
}
|
|
1183
|
+
};
|
|
1184
|
+
`;
|
|
1185
|
+
const blob = new Blob([workerCode], { type: "application/javascript" });
|
|
1186
|
+
return URL.createObjectURL(blob);
|
|
1187
|
+
}
|
|
1188
|
+
var ProofWorker = class _ProofWorker {
|
|
1189
|
+
worker = null;
|
|
1190
|
+
pendingRequests = /* @__PURE__ */ new Map();
|
|
1191
|
+
_isReady = false;
|
|
1192
|
+
requestCounter = 0;
|
|
1193
|
+
/**
|
|
1194
|
+
* Check if Web Workers are supported
|
|
1195
|
+
*/
|
|
1196
|
+
static isSupported() {
|
|
1197
|
+
return typeof Worker !== "undefined" && typeof Blob !== "undefined";
|
|
1198
|
+
}
|
|
1199
|
+
/**
|
|
1200
|
+
* Check if worker is initialized and ready
|
|
1201
|
+
*/
|
|
1202
|
+
get isReady() {
|
|
1203
|
+
return this._isReady;
|
|
1204
|
+
}
|
|
1205
|
+
/**
|
|
1206
|
+
* Initialize the worker
|
|
1207
|
+
*/
|
|
1208
|
+
async initialize(config) {
|
|
1209
|
+
if (this._isReady) {
|
|
1210
|
+
return;
|
|
1211
|
+
}
|
|
1212
|
+
if (!_ProofWorker.isSupported()) {
|
|
1213
|
+
throw new Error("Web Workers not supported in this environment");
|
|
1214
|
+
}
|
|
1215
|
+
const workerURL = createWorkerBlobURL();
|
|
1216
|
+
this.worker = new Worker(workerURL, { type: "module" });
|
|
1217
|
+
this.worker.onmessage = (event) => {
|
|
1218
|
+
this.handleWorkerMessage(event.data);
|
|
1219
|
+
};
|
|
1220
|
+
this.worker.onerror = (error) => {
|
|
1221
|
+
console.error("[ProofWorker] Worker error:", error);
|
|
1222
|
+
for (const [id, { reject }] of this.pendingRequests) {
|
|
1223
|
+
reject(new Error(`Worker error: ${error.message}`));
|
|
1224
|
+
this.pendingRequests.delete(id);
|
|
1225
|
+
}
|
|
1226
|
+
};
|
|
1227
|
+
await this.sendRequest("init", void 0, config);
|
|
1228
|
+
this._isReady = true;
|
|
1229
|
+
URL.revokeObjectURL(workerURL);
|
|
1230
|
+
}
|
|
1231
|
+
/**
|
|
1232
|
+
* Generate a proof using the worker
|
|
1233
|
+
*/
|
|
1234
|
+
async generateProof(type, params, onProgress) {
|
|
1235
|
+
if (!this._isReady || !this.worker) {
|
|
1236
|
+
throw new Error("Worker not initialized. Call initialize() first.");
|
|
1237
|
+
}
|
|
1238
|
+
const messageType = type === "funding" ? "generateFundingProof" : type === "validity" ? "generateValidityProof" : "generateFulfillmentProof";
|
|
1239
|
+
return this.sendRequest(messageType, params, void 0, onProgress);
|
|
1240
|
+
}
|
|
1241
|
+
/**
|
|
1242
|
+
* Destroy the worker and free resources
|
|
1243
|
+
*/
|
|
1244
|
+
async destroy() {
|
|
1245
|
+
if (this.worker) {
|
|
1246
|
+
try {
|
|
1247
|
+
await this.sendRequest("destroy");
|
|
1248
|
+
} catch {
|
|
1249
|
+
}
|
|
1250
|
+
this.worker.terminate();
|
|
1251
|
+
this.worker = null;
|
|
1252
|
+
}
|
|
1253
|
+
this._isReady = false;
|
|
1254
|
+
this.pendingRequests.clear();
|
|
1255
|
+
}
|
|
1256
|
+
/**
|
|
1257
|
+
* Send a request to the worker
|
|
1258
|
+
*/
|
|
1259
|
+
sendRequest(type, params, config, onProgress) {
|
|
1260
|
+
return new Promise((resolve, reject) => {
|
|
1261
|
+
if (!this.worker) {
|
|
1262
|
+
reject(new Error("Worker not available"));
|
|
1263
|
+
return;
|
|
1264
|
+
}
|
|
1265
|
+
const id = `req_${++this.requestCounter}_${Date.now()}`;
|
|
1266
|
+
this.pendingRequests.set(id, { resolve, reject, onProgress });
|
|
1267
|
+
const request = { id, type, params, config };
|
|
1268
|
+
this.worker.postMessage(request);
|
|
1269
|
+
});
|
|
1270
|
+
}
|
|
1271
|
+
/**
|
|
1272
|
+
* Handle messages from the worker
|
|
1273
|
+
*/
|
|
1274
|
+
handleWorkerMessage(response) {
|
|
1275
|
+
const pending = this.pendingRequests.get(response.id);
|
|
1276
|
+
if (!pending) {
|
|
1277
|
+
console.warn("[ProofWorker] Received response for unknown request:", response.id);
|
|
1278
|
+
return;
|
|
1279
|
+
}
|
|
1280
|
+
switch (response.type) {
|
|
1281
|
+
case "success":
|
|
1282
|
+
this.pendingRequests.delete(response.id);
|
|
1283
|
+
pending.resolve(response.result);
|
|
1284
|
+
break;
|
|
1285
|
+
case "error":
|
|
1286
|
+
this.pendingRequests.delete(response.id);
|
|
1287
|
+
pending.reject(new Error(response.error));
|
|
1288
|
+
break;
|
|
1289
|
+
case "progress":
|
|
1290
|
+
if (pending.onProgress && response.progress) {
|
|
1291
|
+
pending.onProgress(response.progress);
|
|
1292
|
+
}
|
|
1293
|
+
break;
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
};
|
|
825
1297
|
export {
|
|
826
1298
|
ATTESTATION_VERSION,
|
|
827
1299
|
BaseWalletAdapter,
|
|
@@ -864,6 +1336,7 @@ export {
|
|
|
864
1336
|
ProofError,
|
|
865
1337
|
ProofGenerationError,
|
|
866
1338
|
ProofNotImplementedError,
|
|
1339
|
+
ProofWorker,
|
|
867
1340
|
ProposalStatus,
|
|
868
1341
|
ReportStatus,
|
|
869
1342
|
SIP,
|
|
@@ -882,6 +1355,7 @@ export {
|
|
|
882
1355
|
ZcashRPCClient,
|
|
883
1356
|
ZcashRPCError,
|
|
884
1357
|
ZcashShieldedService,
|
|
1358
|
+
ZcashSwapService,
|
|
885
1359
|
addBlindings,
|
|
886
1360
|
addCommitments,
|
|
887
1361
|
addOracle,
|
|
@@ -890,6 +1364,7 @@ export {
|
|
|
890
1364
|
bytesToHex as browserBytesToHex,
|
|
891
1365
|
hexToBytes as browserHexToBytes,
|
|
892
1366
|
checkEd25519StealthAddress,
|
|
1367
|
+
checkMobileWASMCompatibility,
|
|
893
1368
|
checkStealthAddress,
|
|
894
1369
|
commit,
|
|
895
1370
|
commitZero,
|
|
@@ -914,8 +1389,10 @@ export {
|
|
|
914
1389
|
createSolanaAdapter,
|
|
915
1390
|
createTrezorAdapter,
|
|
916
1391
|
createWalletFactory,
|
|
1392
|
+
createWorkerBlobURL,
|
|
917
1393
|
createZcashClient,
|
|
918
1394
|
createZcashShieldedService,
|
|
1395
|
+
createZcashSwapService,
|
|
919
1396
|
decodeStealthMetaAddress,
|
|
920
1397
|
decryptMemo,
|
|
921
1398
|
decryptWithViewing,
|
|
@@ -927,6 +1404,8 @@ export {
|
|
|
927
1404
|
deserializeIntent,
|
|
928
1405
|
deserializePayment,
|
|
929
1406
|
detectEthereumWallets,
|
|
1407
|
+
detectMobileBrowser,
|
|
1408
|
+
detectMobilePlatform,
|
|
930
1409
|
detectSolanaWallets,
|
|
931
1410
|
ed25519PublicKeyToNearAddress,
|
|
932
1411
|
ed25519PublicKeyToSolanaAddress,
|
|
@@ -947,6 +1426,7 @@ export {
|
|
|
947
1426
|
getActiveOracles,
|
|
948
1427
|
getAvailableTransports,
|
|
949
1428
|
getBrowserInfo,
|
|
1429
|
+
getBrowserVersion,
|
|
950
1430
|
getChainNumericId,
|
|
951
1431
|
getChainsForStablecoin,
|
|
952
1432
|
getCurveForChain,
|
|
@@ -956,6 +1436,8 @@ export {
|
|
|
956
1436
|
getEthereumProvider,
|
|
957
1437
|
getGenerators,
|
|
958
1438
|
getIntentSummary,
|
|
1439
|
+
getMobileDeviceInfo,
|
|
1440
|
+
getOSVersion,
|
|
959
1441
|
getPaymentSummary,
|
|
960
1442
|
getPaymentTimeRemaining,
|
|
961
1443
|
getPrivacyConfig,
|
|
@@ -981,6 +1463,7 @@ export {
|
|
|
981
1463
|
isSIPError,
|
|
982
1464
|
isStablecoin,
|
|
983
1465
|
isStablecoinOnChain,
|
|
1466
|
+
isTablet,
|
|
984
1467
|
isValidAmount,
|
|
985
1468
|
isValidChainId,
|
|
986
1469
|
isValidCompressedPublicKey,
|
|
@@ -1012,7 +1495,10 @@ export {
|
|
|
1012
1495
|
subtractBlindings,
|
|
1013
1496
|
subtractCommitments,
|
|
1014
1497
|
supportsSharedArrayBuffer,
|
|
1498
|
+
supportsTouch,
|
|
1015
1499
|
supportsViewingKey,
|
|
1500
|
+
supportsWASMBulkMemory,
|
|
1501
|
+
supportsWASMSimd,
|
|
1016
1502
|
supportsWebBluetooth,
|
|
1017
1503
|
supportsWebHID,
|
|
1018
1504
|
supportsWebUSB,
|