@cofhe/sdk 0.4.0 → 0.5.1
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/CHANGELOG.md +38 -0
- package/adapters/{ethers5.test.ts → test/ethers5.test.ts} +2 -2
- package/adapters/{ethers6.test.ts → test/ethers6.test.ts} +2 -2
- package/adapters/{hardhat.hh2.test.ts → test/hardhat.hh2.test.ts} +2 -2
- package/adapters/{index.test.ts → test/index.test.ts} +1 -1
- package/adapters/{wagmi.test.ts → test/wagmi.test.ts} +1 -1
- package/chains/{chains.test.ts → test/chains.test.ts} +1 -1
- package/core/client.ts +11 -1
- package/core/clientTypes.ts +3 -1
- package/core/consts.ts +9 -0
- package/core/decrypt/cofheMocksDecryptForTx.ts +14 -3
- package/core/decrypt/decryptForTxBuilder.ts +16 -2
- package/core/decrypt/decryptForViewBuilder.ts +14 -7
- package/core/decrypt/polling.ts +14 -0
- package/core/decrypt/tnDecryptV2.ts +250 -110
- package/core/decrypt/tnSealOutputV2.ts +245 -104
- package/core/decrypt/verifyDecryptResult.ts +65 -0
- package/core/encrypt/cofheMocksZkVerifySign.ts +6 -6
- package/core/encrypt/zkPackProveVerify.ts +10 -19
- package/core/fetchKeys.ts +0 -2
- package/core/index.ts +9 -1
- package/core/keyStore.ts +5 -2
- package/core/permits.ts +5 -0
- package/core/{client.test.ts → test/client.test.ts} +7 -7
- package/core/{config.test.ts → test/config.test.ts} +1 -1
- package/core/test/decrypt.test.ts +252 -0
- package/core/test/decryptBuilders.test.ts +390 -0
- package/core/{encrypt → test}/encryptInputsBuilder.test.ts +61 -6
- package/core/{fetchKeys.test.ts → test/fetchKeys.test.ts} +3 -3
- package/core/{keyStore.test.ts → test/keyStore.test.ts} +5 -3
- package/core/{permits.test.ts → test/permits.test.ts} +42 -1
- package/core/test/pollCallbacks.test.ts +563 -0
- package/core/types.ts +13 -0
- package/dist/chains.d.cts +2 -2
- package/dist/chains.d.ts +2 -2
- package/dist/chunk-4FP4V35O.js +13 -0
- package/dist/{chunk-NWDKXBIP.js → chunk-MRCKUMOS.js} +62 -22
- package/dist/{chunk-MXND5SVN.js → chunk-S7OKGLFD.js} +485 -207
- package/dist/{clientTypes-kkrRdawm.d.ts → clientTypes-BSbwairE.d.cts} +23 -6
- package/dist/{clientTypes-ACVWbrXL.d.cts → clientTypes-DDmcgZ0a.d.ts} +23 -6
- package/dist/core.cjs +561 -244
- package/dist/core.d.cts +24 -6
- package/dist/core.d.ts +24 -6
- package/dist/core.js +3 -2
- package/dist/node.cjs +566 -246
- package/dist/node.d.cts +3 -3
- package/dist/node.d.ts +3 -3
- package/dist/node.js +14 -7
- package/dist/{permit-MZ502UBl.d.cts → permit-DnVMDT5h.d.cts} +34 -4
- package/dist/{permit-MZ502UBl.d.ts → permit-DnVMDT5h.d.ts} +34 -4
- package/dist/permits.cjs +66 -29
- package/dist/permits.d.cts +18 -13
- package/dist/permits.d.ts +18 -13
- package/dist/permits.js +2 -1
- package/dist/web.cjs +604 -256
- package/dist/web.d.cts +8 -4
- package/dist/web.d.ts +8 -4
- package/dist/web.js +49 -14
- package/dist/zkProve.worker.cjs +72 -64
- package/dist/zkProve.worker.js +71 -64
- package/node/index.ts +13 -4
- package/node/test/client.test.ts +25 -0
- package/node/test/config.test.ts +16 -0
- package/node/test/inherited.test.ts +244 -0
- package/node/test/tfheinit.test.ts +56 -0
- package/package.json +24 -22
- package/permits/permit.ts +31 -5
- package/permits/sealing.ts +1 -1
- package/permits/{localstorage.test.ts → test/localstorage.test.ts} +2 -2
- package/permits/{permit.test.ts → test/permit.test.ts} +35 -1
- package/permits/{sealing.test.ts → test/sealing.test.ts} +1 -1
- package/permits/{store.test.ts → test/store.test.ts} +2 -2
- package/permits/{validation.test.ts → test/validation.test.ts} +82 -6
- package/permits/types.ts +1 -1
- package/permits/validation.ts +42 -2
- package/web/const.ts +2 -0
- package/web/index.ts +40 -11
- package/web/storage.ts +18 -3
- package/web/{client.web.test.ts → test/client.web.test.ts} +13 -1
- package/web/test/config.web.test.ts +16 -0
- package/web/test/inherited.web.test.ts +245 -0
- package/web/test/tfheinit.web.test.ts +62 -0
- package/web/{worker.config.web.test.ts → test/worker.config.web.test.ts} +1 -1
- package/web/{worker.output.web.test.ts → test/worker.output.web.test.ts} +1 -1
- package/web/{workerManager.test.ts → test/workerManager.test.ts} +1 -1
- package/web/{workerManager.web.test.ts → test/workerManager.web.test.ts} +1 -1
- package/web/zkProve.worker.ts +94 -84
- package/node/client.test.ts +0 -147
- package/node/config.test.ts +0 -68
- package/node/encryptInputs.test.ts +0 -155
- package/web/config.web.test.ts +0 -69
- package/web/encryptInputs.web.test.ts +0 -172
- package/web/worker.builder.web.test.ts +0 -148
- /package/dist/{types-YiAC4gig.d.cts → types-C07FK-cL.d.cts} +0 -0
- /package/dist/{types-YiAC4gig.d.ts → types-C07FK-cL.d.ts} +0 -0
package/dist/web.cjs
CHANGED
|
@@ -9,31 +9,11 @@ var middleware = require('zustand/middleware');
|
|
|
9
9
|
var immer = require('immer');
|
|
10
10
|
var nacl = require('tweetnacl');
|
|
11
11
|
var iframeSharedStorage = require('iframe-shared-storage');
|
|
12
|
-
var init = require('tfhe');
|
|
13
12
|
|
|
14
13
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
15
14
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
if (e && e.__esModule) return e;
|
|
19
|
-
var n = Object.create(null);
|
|
20
|
-
if (e) {
|
|
21
|
-
Object.keys(e).forEach(function (k) {
|
|
22
|
-
if (k !== 'default') {
|
|
23
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
24
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
25
|
-
enumerable: true,
|
|
26
|
-
get: function () { return e[k]; }
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
n.default = e;
|
|
32
|
-
return Object.freeze(n);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
var nacl__namespace = /*#__PURE__*/_interopNamespace(nacl);
|
|
36
|
-
var init__default = /*#__PURE__*/_interopDefault(init);
|
|
16
|
+
var nacl__default = /*#__PURE__*/_interopDefault(nacl);
|
|
37
17
|
|
|
38
18
|
// core/client.ts
|
|
39
19
|
|
|
@@ -126,6 +106,16 @@ var bigintSafeJsonStringify = (value) => {
|
|
|
126
106
|
};
|
|
127
107
|
var isCofheError = (error) => error instanceof CofheError;
|
|
128
108
|
|
|
109
|
+
// core/consts.ts
|
|
110
|
+
var TASK_MANAGER_ADDRESS = "0xeA30c4B8b44078Bbf8a6ef5b9f1eC1626C7848D9";
|
|
111
|
+
var MOCKS_ZK_VERIFIER_ADDRESS = "0x0000000000000000000000000000000000005001";
|
|
112
|
+
var MOCKS_THRESHOLD_NETWORK_ADDRESS = "0x0000000000000000000000000000000000005002";
|
|
113
|
+
var MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY = "0x6C8D7F768A6BB4AAFE85E8A2F5A9680355239C7E14646ED62B044E39DE154512";
|
|
114
|
+
var MOCKS_DECRYPT_RESULT_SIGNER_PRIVATE_KEY = "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d";
|
|
115
|
+
var TFHE_RS_ZK_MAX_BITS = 2048;
|
|
116
|
+
var TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT = BigInt(1 << 30);
|
|
117
|
+
var TFHE_RS_KEY_VERSION = 2;
|
|
118
|
+
|
|
129
119
|
// core/types.ts
|
|
130
120
|
var FheUintUTypes = [
|
|
131
121
|
2 /* Uint8 */,
|
|
@@ -248,7 +238,6 @@ var MAX_UINT32 = 4294967295n;
|
|
|
248
238
|
var MAX_UINT64 = 18446744073709551615n;
|
|
249
239
|
var MAX_UINT128 = 340282366920938463463374607431768211455n;
|
|
250
240
|
var MAX_UINT160 = 1461501637330902918203684832716283019655932542975n;
|
|
251
|
-
var MAX_ENCRYPTABLE_BITS = 2048;
|
|
252
241
|
var zkPack = (items, builder) => {
|
|
253
242
|
let totalBits = 0;
|
|
254
243
|
for (const item of items) {
|
|
@@ -312,14 +301,14 @@ var zkPack = (items, builder) => {
|
|
|
312
301
|
}
|
|
313
302
|
}
|
|
314
303
|
}
|
|
315
|
-
if (totalBits >
|
|
304
|
+
if (totalBits > TFHE_RS_ZK_MAX_BITS) {
|
|
316
305
|
throw new CofheError({
|
|
317
306
|
code: "ZK_PACK_FAILED" /* ZkPackFailed */,
|
|
318
|
-
message: `Total bits ${totalBits} exceeds ${
|
|
319
|
-
hint: `Ensure that the total bits of the items to encrypt does not exceed ${
|
|
307
|
+
message: `Total bits ${totalBits} exceeds ${TFHE_RS_ZK_MAX_BITS}`,
|
|
308
|
+
hint: `Ensure that the total bits of the items to encrypt does not exceed ${TFHE_RS_ZK_MAX_BITS}`,
|
|
320
309
|
context: {
|
|
321
310
|
totalBits,
|
|
322
|
-
maxBits:
|
|
311
|
+
maxBits: TFHE_RS_ZK_MAX_BITS,
|
|
323
312
|
items
|
|
324
313
|
}
|
|
325
314
|
});
|
|
@@ -338,7 +327,7 @@ var zkProve = async (builder, crs, metadata) => {
|
|
|
338
327
|
1
|
|
339
328
|
// ZkComputeLoad.Verify
|
|
340
329
|
);
|
|
341
|
-
resolve(compactList.
|
|
330
|
+
resolve(compactList.safe_serialize(TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT));
|
|
342
331
|
}, 0);
|
|
343
332
|
});
|
|
344
333
|
};
|
|
@@ -514,15 +503,6 @@ var MockZkVerifierAbi = [
|
|
|
514
503
|
},
|
|
515
504
|
{ type: "error", name: "InvalidInputs", inputs: [] }
|
|
516
505
|
];
|
|
517
|
-
|
|
518
|
-
// core/consts.ts
|
|
519
|
-
var TASK_MANAGER_ADDRESS = "0xeA30c4B8b44078Bbf8a6ef5b9f1eC1626C7848D9";
|
|
520
|
-
var MOCKS_ZK_VERIFIER_ADDRESS = "0x0000000000000000000000000000000000005001";
|
|
521
|
-
var MOCKS_THRESHOLD_NETWORK_ADDRESS = "0x0000000000000000000000000000000000005002";
|
|
522
|
-
var MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY = "0x6C8D7F768A6BB4AAFE85E8A2F5A9680355239C7E14646ED62B044E39DE154512";
|
|
523
|
-
var MOCKS_DECRYPT_RESULT_SIGNER_PRIVATE_KEY = "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d";
|
|
524
|
-
|
|
525
|
-
// core/encrypt/cofheMocksZkVerifySign.ts
|
|
526
506
|
function createMockZkVerifierSigner() {
|
|
527
507
|
return viem.createWalletClient({
|
|
528
508
|
chain: chains.hardhat,
|
|
@@ -564,14 +544,14 @@ async function cofheMocksCheckEncryptableBits(items) {
|
|
|
564
544
|
}
|
|
565
545
|
}
|
|
566
546
|
}
|
|
567
|
-
if (totalBits >
|
|
547
|
+
if (totalBits > TFHE_RS_ZK_MAX_BITS) {
|
|
568
548
|
throw new CofheError({
|
|
569
549
|
code: "ZK_PACK_FAILED" /* ZkPackFailed */,
|
|
570
|
-
message: `Total bits ${totalBits} exceeds ${
|
|
571
|
-
hint: `Ensure that the total bits of the items to encrypt does not exceed ${
|
|
550
|
+
message: `Total bits ${totalBits} exceeds ${TFHE_RS_ZK_MAX_BITS}`,
|
|
551
|
+
hint: `Ensure that the total bits of the items to encrypt does not exceed ${TFHE_RS_ZK_MAX_BITS}`,
|
|
572
552
|
context: {
|
|
573
553
|
totalBits,
|
|
574
|
-
maxBits:
|
|
554
|
+
maxBits: TFHE_RS_ZK_MAX_BITS,
|
|
575
555
|
items
|
|
576
556
|
}
|
|
577
557
|
});
|
|
@@ -842,6 +822,7 @@ function getThresholdNetworkUrlOrThrow(config, chainId) {
|
|
|
842
822
|
}
|
|
843
823
|
return url;
|
|
844
824
|
}
|
|
825
|
+
var KEYSTORE_NAME = `cofhesdk-keys-v${TFHE_RS_KEY_VERSION}`;
|
|
845
826
|
function isValidPersistedState(state) {
|
|
846
827
|
if (state && typeof state === "object") {
|
|
847
828
|
if ("fhe" in state && "crs" in state) {
|
|
@@ -896,7 +877,7 @@ function createKeysStore(storage) {
|
|
|
896
877
|
};
|
|
897
878
|
const clearKeysStorage = async () => {
|
|
898
879
|
if (storage) {
|
|
899
|
-
await storage.removeItem(
|
|
880
|
+
await storage.removeItem(KEYSTORE_NAME);
|
|
900
881
|
}
|
|
901
882
|
};
|
|
902
883
|
const rehydrateKeysStore = async () => {
|
|
@@ -926,7 +907,7 @@ function createStoreWithPersit(storage) {
|
|
|
926
907
|
if (_error)
|
|
927
908
|
throw new Error(`onRehydrateStorage: Error rehydrating keys store: ${_error}`);
|
|
928
909
|
},
|
|
929
|
-
name:
|
|
910
|
+
name: KEYSTORE_NAME,
|
|
930
911
|
storage: middleware.createJSONStorage(() => storage),
|
|
931
912
|
merge: (persistedState, currentState) => {
|
|
932
913
|
const persisted = isValidPersistedState(persistedState) ? persistedState : DEFAULT_KEYS_STORE;
|
|
@@ -1651,7 +1632,7 @@ var SealingKey = class _SealingKey {
|
|
|
1651
1632
|
const ephemPublicKey = parsedData.public_key instanceof Uint8Array ? parsedData.public_key : new Uint8Array(parsedData.public_key);
|
|
1652
1633
|
const dataToDecrypt = parsedData.data instanceof Uint8Array ? parsedData.data : new Uint8Array(parsedData.data);
|
|
1653
1634
|
const privateKeyBytes = fromHexString(this.privateKey);
|
|
1654
|
-
const decryptedMessage =
|
|
1635
|
+
const decryptedMessage = nacl__default.default.box.open(dataToDecrypt, nonce, ephemPublicKey, privateKeyBytes);
|
|
1655
1636
|
if (!decryptedMessage) {
|
|
1656
1637
|
throw new Error("Failed to decrypt message");
|
|
1657
1638
|
}
|
|
@@ -1684,9 +1665,9 @@ var SealingKey = class _SealingKey {
|
|
|
1684
1665
|
static seal = (value, publicKey) => {
|
|
1685
1666
|
isString(publicKey);
|
|
1686
1667
|
isBigIntOrNumber(value);
|
|
1687
|
-
const ephemeralKeyPair =
|
|
1688
|
-
const nonce =
|
|
1689
|
-
const encryptedMessage =
|
|
1668
|
+
const ephemeralKeyPair = nacl__default.default.box.keyPair();
|
|
1669
|
+
const nonce = nacl__default.default.randomBytes(nacl__default.default.box.nonceLength);
|
|
1670
|
+
const encryptedMessage = nacl__default.default.box(toBeArray(value), nonce, fromHexString(publicKey), ephemeralKeyPair.secretKey);
|
|
1690
1671
|
return {
|
|
1691
1672
|
data: encryptedMessage,
|
|
1692
1673
|
public_key: ephemeralKeyPair.publicKey,
|
|
@@ -1695,7 +1676,7 @@ var SealingKey = class _SealingKey {
|
|
|
1695
1676
|
};
|
|
1696
1677
|
};
|
|
1697
1678
|
var GenerateSealingKey = () => {
|
|
1698
|
-
const sodiumKeypair =
|
|
1679
|
+
const sodiumKeypair = nacl__default.default.box.keyPair();
|
|
1699
1680
|
return new SealingKey(toHexString2(sodiumKeypair.secretKey), toHexString2(sodiumKeypair.publicKey));
|
|
1700
1681
|
};
|
|
1701
1682
|
var SerializedSealingPair = zod.z.object({
|
|
@@ -1853,9 +1834,9 @@ var ValidationUtils = {
|
|
|
1853
1834
|
return false;
|
|
1854
1835
|
},
|
|
1855
1836
|
/**
|
|
1856
|
-
*
|
|
1837
|
+
* Checks that a permit is signed and not expired.
|
|
1857
1838
|
*/
|
|
1858
|
-
|
|
1839
|
+
isSignedAndNotExpired: (permit) => {
|
|
1859
1840
|
if (ValidationUtils.isExpired(permit)) {
|
|
1860
1841
|
return { valid: false, error: "expired" };
|
|
1861
1842
|
}
|
|
@@ -1863,6 +1844,34 @@ var ValidationUtils = {
|
|
|
1863
1844
|
return { valid: false, error: "not-signed" };
|
|
1864
1845
|
}
|
|
1865
1846
|
return { valid: true, error: null };
|
|
1847
|
+
},
|
|
1848
|
+
/**
|
|
1849
|
+
* Asserts that a permit is signed and not expired.
|
|
1850
|
+
*
|
|
1851
|
+
* Throws `Error` with message:
|
|
1852
|
+
* - `Permit is expired`
|
|
1853
|
+
* - `Permit is not signed`
|
|
1854
|
+
*/
|
|
1855
|
+
assertSignedAndNotExpired: (permit) => {
|
|
1856
|
+
const result = ValidationUtils.isSignedAndNotExpired(permit);
|
|
1857
|
+
if (result.valid)
|
|
1858
|
+
return;
|
|
1859
|
+
if (result.error === "expired") {
|
|
1860
|
+
throw new Error("Permit is expired");
|
|
1861
|
+
}
|
|
1862
|
+
if (result.error === "not-signed") {
|
|
1863
|
+
throw new Error("Permit is not signed");
|
|
1864
|
+
}
|
|
1865
|
+
throw new Error("Permit is invalid");
|
|
1866
|
+
},
|
|
1867
|
+
isValid: (permit) => {
|
|
1868
|
+
const schema = permit.type === "self" ? SelfPermitValidator : permit.type === "sharing" ? SharingPermitValidator : permit.type === "recipient" ? ImportPermitValidator : null;
|
|
1869
|
+
if (schema == null)
|
|
1870
|
+
return { valid: false, error: "invalid-schema" };
|
|
1871
|
+
const schemaResult = schema.safeParse(permit);
|
|
1872
|
+
if (!schemaResult.success)
|
|
1873
|
+
return { valid: false, error: "invalid-schema" };
|
|
1874
|
+
return ValidationUtils.isSignedAndNotExpired(permit);
|
|
1866
1875
|
}
|
|
1867
1876
|
};
|
|
1868
1877
|
|
|
@@ -2244,9 +2253,9 @@ var PermitUtils = {
|
|
|
2244
2253
|
};
|
|
2245
2254
|
},
|
|
2246
2255
|
/**
|
|
2247
|
-
* Validate a permit
|
|
2256
|
+
* Validate a permit (schema-level validation)
|
|
2248
2257
|
*/
|
|
2249
|
-
|
|
2258
|
+
validateSchema: (permit) => {
|
|
2250
2259
|
if (permit.type === "self") {
|
|
2251
2260
|
return validateSelfPermit(permit);
|
|
2252
2261
|
} else if (permit.type === "sharing") {
|
|
@@ -2257,12 +2266,27 @@ var PermitUtils = {
|
|
|
2257
2266
|
throw new Error("Invalid permit type");
|
|
2258
2267
|
}
|
|
2259
2268
|
},
|
|
2269
|
+
/**
|
|
2270
|
+
* Validate a permit (holistic validation).
|
|
2271
|
+
*
|
|
2272
|
+
* This validates:
|
|
2273
|
+
* - Permit schema (shape + invariants)
|
|
2274
|
+
* - Permit is signed
|
|
2275
|
+
* - Permit is not expired
|
|
2276
|
+
*
|
|
2277
|
+
* For schema-only validation, use `validateSchema(permit)`.
|
|
2278
|
+
*/
|
|
2279
|
+
validate: (permit) => {
|
|
2280
|
+
const validated = PermitUtils.validateSchema(permit);
|
|
2281
|
+
ValidationUtils.assertSignedAndNotExpired(validated);
|
|
2282
|
+
return validated;
|
|
2283
|
+
},
|
|
2260
2284
|
/**
|
|
2261
2285
|
* Get the permission object from a permit (for use in contracts)
|
|
2262
2286
|
*/
|
|
2263
2287
|
getPermission: (permit, skipValidation = false) => {
|
|
2264
2288
|
if (!skipValidation) {
|
|
2265
|
-
PermitUtils.
|
|
2289
|
+
PermitUtils.validateSchema(permit);
|
|
2266
2290
|
}
|
|
2267
2291
|
return {
|
|
2268
2292
|
issuer: permit.issuer,
|
|
@@ -2328,8 +2352,17 @@ var PermitUtils = {
|
|
|
2328
2352
|
return ValidationUtils.isSigned(permit);
|
|
2329
2353
|
},
|
|
2330
2354
|
/**
|
|
2331
|
-
* Check if permit is
|
|
2355
|
+
* Check if permit is signed and not expired
|
|
2356
|
+
*/
|
|
2357
|
+
isSignedAndNotExpired: (permit) => {
|
|
2358
|
+
return ValidationUtils.isSignedAndNotExpired(permit);
|
|
2359
|
+
},
|
|
2360
|
+
/**
|
|
2361
|
+
* Assert that permit is signed and not expired
|
|
2332
2362
|
*/
|
|
2363
|
+
assertSignedAndNotExpired: (permit) => {
|
|
2364
|
+
return ValidationUtils.assertSignedAndNotExpired(permit);
|
|
2365
|
+
},
|
|
2333
2366
|
isValid: (permit) => {
|
|
2334
2367
|
return ValidationUtils.isValid(permit);
|
|
2335
2368
|
},
|
|
@@ -2507,6 +2540,9 @@ var importShared = async (options, publicClient, walletClient) => {
|
|
|
2507
2540
|
var getHash = (permit) => {
|
|
2508
2541
|
return PermitUtils.getHash(permit);
|
|
2509
2542
|
};
|
|
2543
|
+
var exportShared = (permit) => {
|
|
2544
|
+
return PermitUtils.export(permit);
|
|
2545
|
+
};
|
|
2510
2546
|
var serialize = (permit) => {
|
|
2511
2547
|
return PermitUtils.serialize(permit);
|
|
2512
2548
|
};
|
|
@@ -2557,6 +2593,7 @@ var permits = {
|
|
|
2557
2593
|
getOrCreateSelfPermit,
|
|
2558
2594
|
getOrCreateSharingPermit,
|
|
2559
2595
|
getHash,
|
|
2596
|
+
export: exportShared,
|
|
2560
2597
|
serialize,
|
|
2561
2598
|
deserialize,
|
|
2562
2599
|
getPermit: getPermit2,
|
|
@@ -2799,9 +2836,19 @@ async function cofheMocksDecryptForView(ctHash, utype, permit, publicClient) {
|
|
|
2799
2836
|
return unsealed;
|
|
2800
2837
|
}
|
|
2801
2838
|
|
|
2839
|
+
// core/decrypt/polling.ts
|
|
2840
|
+
function computeMinuteRampPollIntervalMs(elapsedMs, params) {
|
|
2841
|
+
const elapsedSeconds = Math.floor(elapsedMs / 1e3);
|
|
2842
|
+
const intervalSeconds = 1 + Math.floor(elapsedSeconds / 60);
|
|
2843
|
+
const intervalMs = intervalSeconds * 1e3;
|
|
2844
|
+
return Math.min(params.maxIntervalMs, Math.max(params.minIntervalMs, intervalMs));
|
|
2845
|
+
}
|
|
2846
|
+
|
|
2802
2847
|
// core/decrypt/tnSealOutputV2.ts
|
|
2803
2848
|
var POLL_INTERVAL_MS = 1e3;
|
|
2804
|
-
var
|
|
2849
|
+
var POLL_MAX_INTERVAL_MS = 1e4;
|
|
2850
|
+
var SEAL_OUTPUT_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
2851
|
+
var SUBMIT_RETRY_INTERVAL_MS = 1e3;
|
|
2805
2852
|
function numberArrayToUint8Array(arr) {
|
|
2806
2853
|
return new Uint8Array(arr);
|
|
2807
2854
|
}
|
|
@@ -2818,93 +2865,193 @@ function convertSealedData(sealed) {
|
|
|
2818
2865
|
nonce: numberArrayToUint8Array(sealed.nonce)
|
|
2819
2866
|
};
|
|
2820
2867
|
}
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
method: "POST",
|
|
2831
|
-
headers: {
|
|
2832
|
-
"Content-Type": "application/json"
|
|
2833
|
-
},
|
|
2834
|
-
body: JSON.stringify(body)
|
|
2835
|
-
});
|
|
2836
|
-
} catch (e) {
|
|
2837
|
-
throw new CofheError({
|
|
2838
|
-
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
2839
|
-
message: `sealOutput request failed`,
|
|
2840
|
-
hint: "Ensure the threshold network URL is valid and reachable.",
|
|
2841
|
-
cause: e instanceof Error ? e : void 0,
|
|
2842
|
-
context: {
|
|
2843
|
-
thresholdNetworkUrl,
|
|
2844
|
-
body
|
|
2845
|
-
}
|
|
2846
|
-
});
|
|
2868
|
+
function getSealedDataFromSubmitResponse(value) {
|
|
2869
|
+
if (value.sealed)
|
|
2870
|
+
return value.sealed;
|
|
2871
|
+
if (Array.isArray(value.sealed_data) && Array.isArray(value.ephemeral_public_key) && Array.isArray(value.nonce)) {
|
|
2872
|
+
return {
|
|
2873
|
+
data: value.sealed_data,
|
|
2874
|
+
public_key: value.ephemeral_public_key,
|
|
2875
|
+
nonce: value.nonce
|
|
2876
|
+
};
|
|
2847
2877
|
}
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
errorMessage = response.statusText || errorMessage;
|
|
2855
|
-
}
|
|
2878
|
+
return void 0;
|
|
2879
|
+
}
|
|
2880
|
+
function parseCompletedSealOutputResponse(params) {
|
|
2881
|
+
const { value, thresholdNetworkUrl, requestId } = params;
|
|
2882
|
+
if (value.is_succeed === false) {
|
|
2883
|
+
const errorMessage = value.error_message || "Unknown error";
|
|
2856
2884
|
throw new CofheError({
|
|
2857
2885
|
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
2858
2886
|
message: `sealOutput request failed: ${errorMessage}`,
|
|
2859
|
-
hint: "Check the threshold network URL and request parameters.",
|
|
2860
2887
|
context: {
|
|
2861
2888
|
thresholdNetworkUrl,
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
body
|
|
2889
|
+
requestId,
|
|
2890
|
+
response: value
|
|
2865
2891
|
}
|
|
2866
2892
|
});
|
|
2867
2893
|
}
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
submitResponse = await response.json();
|
|
2871
|
-
} catch (e) {
|
|
2894
|
+
const sealed = "sealed" in value ? value.sealed : getSealedDataFromSubmitResponse(value);
|
|
2895
|
+
if (!sealed) {
|
|
2872
2896
|
throw new CofheError({
|
|
2873
|
-
code: "
|
|
2874
|
-
message: `
|
|
2875
|
-
cause: e instanceof Error ? e : void 0,
|
|
2897
|
+
code: "SEAL_OUTPUT_RETURNED_NULL" /* SealOutputReturnedNull */,
|
|
2898
|
+
message: `sealOutput request completed but returned no sealed data`,
|
|
2876
2899
|
context: {
|
|
2877
2900
|
thresholdNetworkUrl,
|
|
2878
|
-
|
|
2901
|
+
requestId,
|
|
2902
|
+
response: value
|
|
2879
2903
|
}
|
|
2880
2904
|
});
|
|
2881
2905
|
}
|
|
2882
|
-
|
|
2906
|
+
return convertSealedData(sealed);
|
|
2907
|
+
}
|
|
2908
|
+
async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, permission, overallStartTime, onPoll) {
|
|
2909
|
+
const body = {
|
|
2910
|
+
ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
|
|
2911
|
+
host_chain_id: chainId,
|
|
2912
|
+
permit: permission
|
|
2913
|
+
};
|
|
2914
|
+
let attemptIndex = 0;
|
|
2915
|
+
for (; ; ) {
|
|
2916
|
+
let response;
|
|
2917
|
+
try {
|
|
2918
|
+
response = await fetch(`${thresholdNetworkUrl}/v2/sealoutput`, {
|
|
2919
|
+
method: "POST",
|
|
2920
|
+
headers: {
|
|
2921
|
+
"Content-Type": "application/json"
|
|
2922
|
+
},
|
|
2923
|
+
body: JSON.stringify(body)
|
|
2924
|
+
});
|
|
2925
|
+
} catch (e) {
|
|
2926
|
+
throw new CofheError({
|
|
2927
|
+
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
2928
|
+
message: `sealOutput request failed`,
|
|
2929
|
+
hint: "Ensure the threshold network URL is valid and reachable.",
|
|
2930
|
+
cause: e instanceof Error ? e : void 0,
|
|
2931
|
+
context: {
|
|
2932
|
+
thresholdNetworkUrl,
|
|
2933
|
+
body,
|
|
2934
|
+
attemptIndex
|
|
2935
|
+
}
|
|
2936
|
+
});
|
|
2937
|
+
}
|
|
2938
|
+
if (!response.ok) {
|
|
2939
|
+
let errorMessage = `HTTP ${response.status}`;
|
|
2940
|
+
try {
|
|
2941
|
+
const errorBody = await response.json();
|
|
2942
|
+
errorMessage = errorBody.error_message || errorBody.message || errorMessage;
|
|
2943
|
+
} catch {
|
|
2944
|
+
errorMessage = response.statusText || errorMessage;
|
|
2945
|
+
}
|
|
2946
|
+
throw new CofheError({
|
|
2947
|
+
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
2948
|
+
message: `sealOutput request failed: ${errorMessage}`,
|
|
2949
|
+
hint: "Check the threshold network URL and request parameters.",
|
|
2950
|
+
context: {
|
|
2951
|
+
thresholdNetworkUrl,
|
|
2952
|
+
status: response.status,
|
|
2953
|
+
statusText: response.statusText,
|
|
2954
|
+
body,
|
|
2955
|
+
attemptIndex
|
|
2956
|
+
}
|
|
2957
|
+
});
|
|
2958
|
+
}
|
|
2959
|
+
let submitResponse;
|
|
2960
|
+
if (response.status !== 204) {
|
|
2961
|
+
try {
|
|
2962
|
+
submitResponse = await response.json();
|
|
2963
|
+
} catch (e) {
|
|
2964
|
+
throw new CofheError({
|
|
2965
|
+
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
2966
|
+
message: `Failed to parse sealOutput submit response`,
|
|
2967
|
+
cause: e instanceof Error ? e : void 0,
|
|
2968
|
+
context: {
|
|
2969
|
+
thresholdNetworkUrl,
|
|
2970
|
+
body,
|
|
2971
|
+
attemptIndex
|
|
2972
|
+
}
|
|
2973
|
+
});
|
|
2974
|
+
}
|
|
2975
|
+
if (getSealedDataFromSubmitResponse(submitResponse)) {
|
|
2976
|
+
return {
|
|
2977
|
+
kind: "completed",
|
|
2978
|
+
sealed: parseCompletedSealOutputResponse({
|
|
2979
|
+
value: submitResponse,
|
|
2980
|
+
thresholdNetworkUrl,
|
|
2981
|
+
requestId: submitResponse.request_id
|
|
2982
|
+
})
|
|
2983
|
+
};
|
|
2984
|
+
}
|
|
2985
|
+
if (submitResponse.request_id) {
|
|
2986
|
+
return { kind: "request_id", requestId: submitResponse.request_id };
|
|
2987
|
+
}
|
|
2988
|
+
}
|
|
2989
|
+
if (response.status === 204) {
|
|
2990
|
+
const elapsedMs = Date.now() - overallStartTime;
|
|
2991
|
+
if (elapsedMs > SEAL_OUTPUT_TIMEOUT_MS) {
|
|
2992
|
+
throw new CofheError({
|
|
2993
|
+
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
2994
|
+
message: `sealOutput submit retried without receiving request_id for ${SEAL_OUTPUT_TIMEOUT_MS}ms`,
|
|
2995
|
+
hint: "The ciphertext may still be propagating. Try again later.",
|
|
2996
|
+
context: {
|
|
2997
|
+
thresholdNetworkUrl,
|
|
2998
|
+
body,
|
|
2999
|
+
attemptIndex,
|
|
3000
|
+
timeoutMs: SEAL_OUTPUT_TIMEOUT_MS,
|
|
3001
|
+
submitResponse,
|
|
3002
|
+
status: response.status
|
|
3003
|
+
}
|
|
3004
|
+
});
|
|
3005
|
+
}
|
|
3006
|
+
onPoll?.({
|
|
3007
|
+
operation: "sealoutput",
|
|
3008
|
+
requestId: "",
|
|
3009
|
+
attemptIndex,
|
|
3010
|
+
elapsedMs,
|
|
3011
|
+
intervalMs: SUBMIT_RETRY_INTERVAL_MS,
|
|
3012
|
+
timeoutMs: SEAL_OUTPUT_TIMEOUT_MS
|
|
3013
|
+
});
|
|
3014
|
+
await new Promise((resolve) => setTimeout(resolve, SUBMIT_RETRY_INTERVAL_MS));
|
|
3015
|
+
attemptIndex += 1;
|
|
3016
|
+
continue;
|
|
3017
|
+
}
|
|
2883
3018
|
throw new CofheError({
|
|
2884
3019
|
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
2885
3020
|
message: `sealOutput submit response missing request_id`,
|
|
2886
3021
|
context: {
|
|
2887
3022
|
thresholdNetworkUrl,
|
|
2888
3023
|
body,
|
|
2889
|
-
submitResponse
|
|
3024
|
+
submitResponse,
|
|
3025
|
+
attemptIndex
|
|
2890
3026
|
}
|
|
2891
3027
|
});
|
|
2892
3028
|
}
|
|
2893
|
-
return submitResponse.request_id;
|
|
2894
3029
|
}
|
|
2895
|
-
async function pollSealOutputStatus(thresholdNetworkUrl, requestId) {
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
3030
|
+
async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStartTime, onPoll) {
|
|
3031
|
+
let attemptIndex = 0;
|
|
3032
|
+
while (true) {
|
|
3033
|
+
const elapsedMs = Date.now() - overallStartTime;
|
|
3034
|
+
const intervalMs = computeMinuteRampPollIntervalMs(elapsedMs, {
|
|
3035
|
+
minIntervalMs: POLL_INTERVAL_MS,
|
|
3036
|
+
maxIntervalMs: POLL_MAX_INTERVAL_MS
|
|
3037
|
+
});
|
|
3038
|
+
onPoll?.({
|
|
3039
|
+
operation: "sealoutput",
|
|
3040
|
+
requestId,
|
|
3041
|
+
attemptIndex,
|
|
3042
|
+
elapsedMs,
|
|
3043
|
+
intervalMs,
|
|
3044
|
+
timeoutMs: SEAL_OUTPUT_TIMEOUT_MS
|
|
3045
|
+
});
|
|
3046
|
+
if (elapsedMs > SEAL_OUTPUT_TIMEOUT_MS) {
|
|
2900
3047
|
throw new CofheError({
|
|
2901
3048
|
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
2902
|
-
message: `sealOutput polling timed out after ${
|
|
3049
|
+
message: `sealOutput polling timed out after ${SEAL_OUTPUT_TIMEOUT_MS}ms`,
|
|
2903
3050
|
hint: "The request may still be processing. Try again later.",
|
|
2904
3051
|
context: {
|
|
2905
3052
|
thresholdNetworkUrl,
|
|
2906
3053
|
requestId,
|
|
2907
|
-
timeoutMs:
|
|
3054
|
+
timeoutMs: SEAL_OUTPUT_TIMEOUT_MS
|
|
2908
3055
|
}
|
|
2909
3056
|
});
|
|
2910
3057
|
}
|
|
@@ -2973,32 +3120,14 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId) {
|
|
|
2973
3120
|
});
|
|
2974
3121
|
}
|
|
2975
3122
|
if (statusResponse.status === "COMPLETED") {
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
context: {
|
|
2982
|
-
thresholdNetworkUrl,
|
|
2983
|
-
requestId,
|
|
2984
|
-
statusResponse
|
|
2985
|
-
}
|
|
2986
|
-
});
|
|
2987
|
-
}
|
|
2988
|
-
if (!statusResponse.sealed) {
|
|
2989
|
-
throw new CofheError({
|
|
2990
|
-
code: "SEAL_OUTPUT_RETURNED_NULL" /* SealOutputReturnedNull */,
|
|
2991
|
-
message: `sealOutput request completed but returned no sealed data`,
|
|
2992
|
-
context: {
|
|
2993
|
-
thresholdNetworkUrl,
|
|
2994
|
-
requestId,
|
|
2995
|
-
statusResponse
|
|
2996
|
-
}
|
|
2997
|
-
});
|
|
2998
|
-
}
|
|
2999
|
-
return convertSealedData(statusResponse.sealed);
|
|
3123
|
+
return parseCompletedSealOutputResponse({
|
|
3124
|
+
value: statusResponse,
|
|
3125
|
+
thresholdNetworkUrl,
|
|
3126
|
+
requestId
|
|
3127
|
+
});
|
|
3000
3128
|
}
|
|
3001
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
3129
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
3130
|
+
attemptIndex += 1;
|
|
3002
3131
|
}
|
|
3003
3132
|
throw new CofheError({
|
|
3004
3133
|
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
@@ -3009,9 +3138,21 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId) {
|
|
|
3009
3138
|
}
|
|
3010
3139
|
});
|
|
3011
3140
|
}
|
|
3012
|
-
async function tnSealOutputV2(
|
|
3013
|
-
const
|
|
3014
|
-
|
|
3141
|
+
async function tnSealOutputV2(params) {
|
|
3142
|
+
const { thresholdNetworkUrl, ctHash, chainId, permission, onPoll } = params;
|
|
3143
|
+
const overallStartTime = Date.now();
|
|
3144
|
+
const submitResult = await submitSealOutputRequest(
|
|
3145
|
+
thresholdNetworkUrl,
|
|
3146
|
+
ctHash,
|
|
3147
|
+
chainId,
|
|
3148
|
+
permission,
|
|
3149
|
+
overallStartTime,
|
|
3150
|
+
onPoll
|
|
3151
|
+
);
|
|
3152
|
+
if (submitResult.kind === "completed") {
|
|
3153
|
+
return submitResult.sealed;
|
|
3154
|
+
}
|
|
3155
|
+
return await pollSealOutputStatus(thresholdNetworkUrl, submitResult.requestId, overallStartTime, onPoll);
|
|
3015
3156
|
}
|
|
3016
3157
|
|
|
3017
3158
|
// core/decrypt/decryptForViewBuilder.ts
|
|
@@ -3020,6 +3161,7 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3020
3161
|
utype;
|
|
3021
3162
|
permitHash;
|
|
3022
3163
|
permit;
|
|
3164
|
+
pollCallback;
|
|
3023
3165
|
constructor(params) {
|
|
3024
3166
|
super({
|
|
3025
3167
|
config: params.config,
|
|
@@ -3076,6 +3218,10 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3076
3218
|
getAccount() {
|
|
3077
3219
|
return this.account;
|
|
3078
3220
|
}
|
|
3221
|
+
onPoll(callback) {
|
|
3222
|
+
this.pollCallback = callback;
|
|
3223
|
+
return this;
|
|
3224
|
+
}
|
|
3079
3225
|
withPermit(permitOrPermitHash) {
|
|
3080
3226
|
if (typeof permitOrPermitHash === "string") {
|
|
3081
3227
|
this.permitHash = permitOrPermitHash;
|
|
@@ -3199,7 +3345,13 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3199
3345
|
this.assertPublicClient();
|
|
3200
3346
|
const thresholdNetworkUrl = await this.getThresholdNetworkUrl();
|
|
3201
3347
|
const permission = PermitUtils.getPermission(permit, true);
|
|
3202
|
-
const sealed = await tnSealOutputV2(
|
|
3348
|
+
const sealed = await tnSealOutputV2({
|
|
3349
|
+
ctHash: this.ctHash,
|
|
3350
|
+
chainId: this.chainId,
|
|
3351
|
+
permission,
|
|
3352
|
+
thresholdNetworkUrl,
|
|
3353
|
+
onPoll: this.pollCallback
|
|
3354
|
+
});
|
|
3203
3355
|
return PermitUtils.unseal(permit, sealed);
|
|
3204
3356
|
}
|
|
3205
3357
|
/**
|
|
@@ -3227,7 +3379,6 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3227
3379
|
this.validateUtypeOrThrow();
|
|
3228
3380
|
const permit = await this.getResolvedPermit();
|
|
3229
3381
|
PermitUtils.validate(permit);
|
|
3230
|
-
PermitUtils.isValid(permit);
|
|
3231
3382
|
const chainId = permit._signedDomain.chainId;
|
|
3232
3383
|
let unsealed;
|
|
3233
3384
|
if (chainId === hardhat2.id) {
|
|
@@ -3238,6 +3389,9 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3238
3389
|
return convertViaUtype(this.utype, unsealed);
|
|
3239
3390
|
}
|
|
3240
3391
|
};
|
|
3392
|
+
var UINT_TYPE_MASK = 0x7fn;
|
|
3393
|
+
var TYPE_BYTE_OFFSET = 8n;
|
|
3394
|
+
var getEncryptionTypeFromCtHash = (ctHash) => Number(ctHash >> TYPE_BYTE_OFFSET & UINT_TYPE_MASK);
|
|
3241
3395
|
async function cofheMocksDecryptForTx(ctHash, utype, permit, publicClient) {
|
|
3242
3396
|
let allowed;
|
|
3243
3397
|
let error;
|
|
@@ -3275,7 +3429,13 @@ async function cofheMocksDecryptForTx(ctHash, utype, permit, publicClient) {
|
|
|
3275
3429
|
message: `mocks decryptForTx call failed: ACL Access Denied (NotAllowed)`
|
|
3276
3430
|
});
|
|
3277
3431
|
}
|
|
3278
|
-
const
|
|
3432
|
+
const chainId = publicClient.chain?.id ?? await publicClient.getChainId();
|
|
3433
|
+
const normalizedCtHash = BigInt(ctHash);
|
|
3434
|
+
const encryptionType = getEncryptionTypeFromCtHash(normalizedCtHash);
|
|
3435
|
+
const packed = viem.encodePacked(
|
|
3436
|
+
["uint256", "uint32", "uint64", "uint256"],
|
|
3437
|
+
[decryptedValue, encryptionType, BigInt(chainId), normalizedCtHash]
|
|
3438
|
+
);
|
|
3279
3439
|
const messageHash = viem.keccak256(packed);
|
|
3280
3440
|
const signature = await accounts.sign({
|
|
3281
3441
|
hash: messageHash,
|
|
@@ -3347,7 +3507,9 @@ function parseDecryptedBytesToBigInt(decrypted) {
|
|
|
3347
3507
|
|
|
3348
3508
|
// core/decrypt/tnDecryptV2.ts
|
|
3349
3509
|
var POLL_INTERVAL_MS2 = 1e3;
|
|
3350
|
-
var
|
|
3510
|
+
var POLL_MAX_INTERVAL_MS2 = 1e4;
|
|
3511
|
+
var DECRYPT_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
3512
|
+
var SUBMIT_RETRY_INTERVAL_MS2 = 1e3;
|
|
3351
3513
|
function assertDecryptSubmitResponseV2(value) {
|
|
3352
3514
|
if (value == null || typeof value !== "object") {
|
|
3353
3515
|
throw new CofheError({
|
|
@@ -3359,16 +3521,65 @@ function assertDecryptSubmitResponseV2(value) {
|
|
|
3359
3521
|
});
|
|
3360
3522
|
}
|
|
3361
3523
|
const v = value;
|
|
3362
|
-
if (
|
|
3524
|
+
if (v.request_id !== null && typeof v.request_id !== "string") {
|
|
3363
3525
|
throw new CofheError({
|
|
3364
3526
|
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3365
|
-
message: "decrypt submit response
|
|
3527
|
+
message: "decrypt submit response has invalid request_id",
|
|
3366
3528
|
context: {
|
|
3367
3529
|
value
|
|
3368
3530
|
}
|
|
3369
3531
|
});
|
|
3370
3532
|
}
|
|
3371
|
-
return {
|
|
3533
|
+
return {
|
|
3534
|
+
request_id: v.request_id ?? null,
|
|
3535
|
+
status: typeof v.status === "string" ? v.status : void 0,
|
|
3536
|
+
is_succeed: typeof v.is_succeed === "boolean" ? v.is_succeed : void 0,
|
|
3537
|
+
decrypted: Array.isArray(v.decrypted) ? v.decrypted : void 0,
|
|
3538
|
+
signature: typeof v.signature === "string" ? v.signature : void 0,
|
|
3539
|
+
encryption_type: typeof v.encryption_type === "number" ? v.encryption_type : void 0,
|
|
3540
|
+
error_message: typeof v.error_message === "string" || v.error_message === null ? v.error_message : void 0,
|
|
3541
|
+
message: typeof v.message === "string" ? v.message : void 0
|
|
3542
|
+
};
|
|
3543
|
+
}
|
|
3544
|
+
function parseCompletedDecryptResponseV2(params) {
|
|
3545
|
+
const { value, thresholdNetworkUrl, requestId } = params;
|
|
3546
|
+
if (value.is_succeed === false) {
|
|
3547
|
+
const errorMessage = value.error_message || "Unknown error";
|
|
3548
|
+
throw new CofheError({
|
|
3549
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3550
|
+
message: `decrypt request failed: ${errorMessage}`,
|
|
3551
|
+
context: {
|
|
3552
|
+
thresholdNetworkUrl,
|
|
3553
|
+
requestId,
|
|
3554
|
+
response: value
|
|
3555
|
+
}
|
|
3556
|
+
});
|
|
3557
|
+
}
|
|
3558
|
+
if (value.error_message) {
|
|
3559
|
+
throw new CofheError({
|
|
3560
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3561
|
+
message: `decrypt request failed: ${value.error_message}`,
|
|
3562
|
+
context: {
|
|
3563
|
+
thresholdNetworkUrl,
|
|
3564
|
+
requestId,
|
|
3565
|
+
response: value
|
|
3566
|
+
}
|
|
3567
|
+
});
|
|
3568
|
+
}
|
|
3569
|
+
if (!Array.isArray(value.decrypted)) {
|
|
3570
|
+
throw new CofheError({
|
|
3571
|
+
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3572
|
+
message: "decrypt completed but response missing <decrypted> byte array",
|
|
3573
|
+
context: {
|
|
3574
|
+
thresholdNetworkUrl,
|
|
3575
|
+
requestId,
|
|
3576
|
+
response: value
|
|
3577
|
+
}
|
|
3578
|
+
});
|
|
3579
|
+
}
|
|
3580
|
+
const decryptedValue = parseDecryptedBytesToBigInt(value.decrypted);
|
|
3581
|
+
const signature = normalizeTnSignature(value.signature);
|
|
3582
|
+
return { decryptedValue, signature };
|
|
3372
3583
|
}
|
|
3373
3584
|
function assertDecryptStatusResponseV2(value) {
|
|
3374
3585
|
if (value == null || typeof value !== "object") {
|
|
@@ -3414,7 +3625,7 @@ function assertDecryptStatusResponseV2(value) {
|
|
|
3414
3625
|
}
|
|
3415
3626
|
return value;
|
|
3416
3627
|
}
|
|
3417
|
-
async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, permission) {
|
|
3628
|
+
async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, permission, overallStartTime, onPoll) {
|
|
3418
3629
|
const body = {
|
|
3419
3630
|
ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
|
|
3420
3631
|
host_chain_id: chainId
|
|
@@ -3422,79 +3633,151 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
|
|
|
3422
3633
|
if (permission) {
|
|
3423
3634
|
body.permit = permission;
|
|
3424
3635
|
}
|
|
3425
|
-
let
|
|
3426
|
-
|
|
3427
|
-
response
|
|
3428
|
-
method: "POST",
|
|
3429
|
-
headers: {
|
|
3430
|
-
"Content-Type": "application/json"
|
|
3431
|
-
},
|
|
3432
|
-
body: JSON.stringify(body)
|
|
3433
|
-
});
|
|
3434
|
-
} catch (e) {
|
|
3435
|
-
throw new CofheError({
|
|
3436
|
-
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3437
|
-
message: `decrypt request failed`,
|
|
3438
|
-
hint: "Ensure the threshold network URL is valid and reachable.",
|
|
3439
|
-
cause: e instanceof Error ? e : void 0,
|
|
3440
|
-
context: {
|
|
3441
|
-
thresholdNetworkUrl,
|
|
3442
|
-
body
|
|
3443
|
-
}
|
|
3444
|
-
});
|
|
3445
|
-
}
|
|
3446
|
-
if (!response.ok) {
|
|
3447
|
-
let errorMessage = `HTTP ${response.status}`;
|
|
3636
|
+
let attemptIndex = 0;
|
|
3637
|
+
for (; ; ) {
|
|
3638
|
+
let response;
|
|
3448
3639
|
try {
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3640
|
+
response = await fetch(`${thresholdNetworkUrl}/v2/decrypt`, {
|
|
3641
|
+
method: "POST",
|
|
3642
|
+
headers: {
|
|
3643
|
+
"Content-Type": "application/json"
|
|
3644
|
+
},
|
|
3645
|
+
body: JSON.stringify(body)
|
|
3646
|
+
});
|
|
3647
|
+
} catch (e) {
|
|
3648
|
+
throw new CofheError({
|
|
3649
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3650
|
+
message: `decrypt request failed`,
|
|
3651
|
+
hint: "Ensure the threshold network URL is valid and reachable.",
|
|
3652
|
+
cause: e instanceof Error ? e : void 0,
|
|
3653
|
+
context: {
|
|
3654
|
+
thresholdNetworkUrl,
|
|
3655
|
+
body,
|
|
3656
|
+
attemptIndex
|
|
3657
|
+
}
|
|
3658
|
+
});
|
|
3455
3659
|
}
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3660
|
+
if (!response.ok) {
|
|
3661
|
+
let errorMessage = `HTTP ${response.status}`;
|
|
3662
|
+
try {
|
|
3663
|
+
const errorBody = await response.json();
|
|
3664
|
+
const maybeMessage = errorBody.error_message || errorBody.message;
|
|
3665
|
+
if (typeof maybeMessage === "string" && maybeMessage.length > 0)
|
|
3666
|
+
errorMessage = maybeMessage;
|
|
3667
|
+
} catch {
|
|
3668
|
+
errorMessage = response.statusText || errorMessage;
|
|
3465
3669
|
}
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3670
|
+
throw new CofheError({
|
|
3671
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3672
|
+
message: `decrypt request failed: ${errorMessage}`,
|
|
3673
|
+
hint: "Check the threshold network URL and request parameters.",
|
|
3674
|
+
context: {
|
|
3675
|
+
thresholdNetworkUrl,
|
|
3676
|
+
status: response.status,
|
|
3677
|
+
statusText: response.statusText,
|
|
3678
|
+
body,
|
|
3679
|
+
attemptIndex
|
|
3680
|
+
}
|
|
3681
|
+
});
|
|
3682
|
+
}
|
|
3683
|
+
let submitResponse;
|
|
3684
|
+
if (response.status !== 204) {
|
|
3685
|
+
let rawJson;
|
|
3686
|
+
try {
|
|
3687
|
+
rawJson = await response.json();
|
|
3688
|
+
} catch (e) {
|
|
3689
|
+
throw new CofheError({
|
|
3690
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3691
|
+
message: `Failed to parse decrypt submit response`,
|
|
3692
|
+
cause: e instanceof Error ? e : void 0,
|
|
3693
|
+
context: {
|
|
3694
|
+
thresholdNetworkUrl,
|
|
3695
|
+
body,
|
|
3696
|
+
attemptIndex
|
|
3697
|
+
}
|
|
3698
|
+
});
|
|
3699
|
+
}
|
|
3700
|
+
submitResponse = assertDecryptSubmitResponseV2(rawJson);
|
|
3701
|
+
if (Array.isArray(submitResponse.decrypted) && typeof submitResponse.signature === "string") {
|
|
3702
|
+
return {
|
|
3703
|
+
kind: "completed",
|
|
3704
|
+
...parseCompletedDecryptResponseV2({
|
|
3705
|
+
value: submitResponse,
|
|
3706
|
+
thresholdNetworkUrl,
|
|
3707
|
+
requestId: submitResponse.request_id
|
|
3708
|
+
})
|
|
3709
|
+
};
|
|
3710
|
+
}
|
|
3711
|
+
if (submitResponse.request_id) {
|
|
3712
|
+
return { kind: "request_id", requestId: submitResponse.request_id };
|
|
3713
|
+
}
|
|
3714
|
+
}
|
|
3715
|
+
if (response.status === 204) {
|
|
3716
|
+
const elapsedMs = Date.now() - overallStartTime;
|
|
3717
|
+
if (elapsedMs > DECRYPT_TIMEOUT_MS) {
|
|
3718
|
+
throw new CofheError({
|
|
3719
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3720
|
+
message: `decrypt submit retried without receiving request_id for ${DECRYPT_TIMEOUT_MS}ms`,
|
|
3721
|
+
hint: "The ciphertext may still be propagating. Try again later.",
|
|
3722
|
+
context: {
|
|
3723
|
+
thresholdNetworkUrl,
|
|
3724
|
+
body,
|
|
3725
|
+
attemptIndex,
|
|
3726
|
+
timeoutMs: DECRYPT_TIMEOUT_MS,
|
|
3727
|
+
submitResponse,
|
|
3728
|
+
status: response.status
|
|
3729
|
+
}
|
|
3730
|
+
});
|
|
3731
|
+
}
|
|
3732
|
+
onPoll?.({
|
|
3733
|
+
operation: "decrypt",
|
|
3734
|
+
requestId: "",
|
|
3735
|
+
attemptIndex,
|
|
3736
|
+
elapsedMs,
|
|
3737
|
+
intervalMs: SUBMIT_RETRY_INTERVAL_MS2,
|
|
3738
|
+
timeoutMs: DECRYPT_TIMEOUT_MS
|
|
3739
|
+
});
|
|
3740
|
+
await new Promise((resolve) => setTimeout(resolve, SUBMIT_RETRY_INTERVAL_MS2));
|
|
3741
|
+
attemptIndex += 1;
|
|
3742
|
+
continue;
|
|
3743
|
+
}
|
|
3472
3744
|
throw new CofheError({
|
|
3473
3745
|
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3474
|
-
message: `
|
|
3475
|
-
cause: e instanceof Error ? e : void 0,
|
|
3746
|
+
message: `decrypt submit response missing request_id`,
|
|
3476
3747
|
context: {
|
|
3477
3748
|
thresholdNetworkUrl,
|
|
3478
|
-
body
|
|
3749
|
+
body,
|
|
3750
|
+
submitResponse,
|
|
3751
|
+
attemptIndex
|
|
3479
3752
|
}
|
|
3480
3753
|
});
|
|
3481
3754
|
}
|
|
3482
|
-
const submitResponse = assertDecryptSubmitResponseV2(rawJson);
|
|
3483
|
-
return submitResponse.request_id;
|
|
3484
3755
|
}
|
|
3485
|
-
async function pollDecryptStatusV2(thresholdNetworkUrl, requestId) {
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3756
|
+
async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartTime, onPoll) {
|
|
3757
|
+
let attemptIndex = 0;
|
|
3758
|
+
while (true) {
|
|
3759
|
+
const elapsedMs = Date.now() - overallStartTime;
|
|
3760
|
+
const intervalMs = computeMinuteRampPollIntervalMs(elapsedMs, {
|
|
3761
|
+
minIntervalMs: POLL_INTERVAL_MS2,
|
|
3762
|
+
maxIntervalMs: POLL_MAX_INTERVAL_MS2
|
|
3763
|
+
});
|
|
3764
|
+
onPoll?.({
|
|
3765
|
+
operation: "decrypt",
|
|
3766
|
+
requestId,
|
|
3767
|
+
attemptIndex,
|
|
3768
|
+
elapsedMs,
|
|
3769
|
+
intervalMs,
|
|
3770
|
+
timeoutMs: DECRYPT_TIMEOUT_MS
|
|
3771
|
+
});
|
|
3772
|
+
if (elapsedMs > DECRYPT_TIMEOUT_MS) {
|
|
3490
3773
|
throw new CofheError({
|
|
3491
3774
|
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3492
|
-
message: `decrypt polling timed out after ${
|
|
3775
|
+
message: `decrypt polling timed out after ${DECRYPT_TIMEOUT_MS}ms`,
|
|
3493
3776
|
hint: "The request may still be processing. Try again later.",
|
|
3494
3777
|
context: {
|
|
3495
3778
|
thresholdNetworkUrl,
|
|
3496
3779
|
requestId,
|
|
3497
|
-
timeoutMs:
|
|
3780
|
+
timeoutMs: DECRYPT_TIMEOUT_MS
|
|
3498
3781
|
}
|
|
3499
3782
|
});
|
|
3500
3783
|
}
|
|
@@ -3566,45 +3849,14 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId) {
|
|
|
3566
3849
|
}
|
|
3567
3850
|
const statusResponse = assertDecryptStatusResponseV2(rawJson);
|
|
3568
3851
|
if (statusResponse.status === "COMPLETED") {
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
context: {
|
|
3575
|
-
thresholdNetworkUrl,
|
|
3576
|
-
requestId,
|
|
3577
|
-
statusResponse
|
|
3578
|
-
}
|
|
3579
|
-
});
|
|
3580
|
-
}
|
|
3581
|
-
if (statusResponse.error_message) {
|
|
3582
|
-
throw new CofheError({
|
|
3583
|
-
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3584
|
-
message: `decrypt request failed: ${statusResponse.error_message}`,
|
|
3585
|
-
context: {
|
|
3586
|
-
thresholdNetworkUrl,
|
|
3587
|
-
requestId,
|
|
3588
|
-
statusResponse
|
|
3589
|
-
}
|
|
3590
|
-
});
|
|
3591
|
-
}
|
|
3592
|
-
if (!Array.isArray(statusResponse.decrypted)) {
|
|
3593
|
-
throw new CofheError({
|
|
3594
|
-
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3595
|
-
message: "decrypt completed but response missing <decrypted> byte array",
|
|
3596
|
-
context: {
|
|
3597
|
-
thresholdNetworkUrl,
|
|
3598
|
-
requestId,
|
|
3599
|
-
statusResponse
|
|
3600
|
-
}
|
|
3601
|
-
});
|
|
3602
|
-
}
|
|
3603
|
-
const decryptedValue = parseDecryptedBytesToBigInt(statusResponse.decrypted);
|
|
3604
|
-
const signature = normalizeTnSignature(statusResponse.signature);
|
|
3605
|
-
return { decryptedValue, signature };
|
|
3852
|
+
return parseCompletedDecryptResponseV2({
|
|
3853
|
+
value: statusResponse,
|
|
3854
|
+
thresholdNetworkUrl,
|
|
3855
|
+
requestId
|
|
3856
|
+
});
|
|
3606
3857
|
}
|
|
3607
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
3858
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
3859
|
+
attemptIndex += 1;
|
|
3608
3860
|
}
|
|
3609
3861
|
throw new CofheError({
|
|
3610
3862
|
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
@@ -3615,9 +3867,21 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId) {
|
|
|
3615
3867
|
}
|
|
3616
3868
|
});
|
|
3617
3869
|
}
|
|
3618
|
-
async function tnDecryptV2(
|
|
3619
|
-
const
|
|
3620
|
-
|
|
3870
|
+
async function tnDecryptV2(params) {
|
|
3871
|
+
const { thresholdNetworkUrl, ctHash, chainId, permission, onPoll } = params;
|
|
3872
|
+
const overallStartTime = Date.now();
|
|
3873
|
+
const submitResult = await submitDecryptRequestV2(
|
|
3874
|
+
thresholdNetworkUrl,
|
|
3875
|
+
ctHash,
|
|
3876
|
+
chainId,
|
|
3877
|
+
permission,
|
|
3878
|
+
overallStartTime,
|
|
3879
|
+
onPoll
|
|
3880
|
+
);
|
|
3881
|
+
if (submitResult.kind === "completed") {
|
|
3882
|
+
return submitResult;
|
|
3883
|
+
}
|
|
3884
|
+
return await pollDecryptStatusV2(thresholdNetworkUrl, submitResult.requestId, overallStartTime, onPoll);
|
|
3621
3885
|
}
|
|
3622
3886
|
|
|
3623
3887
|
// core/decrypt/decryptForTxBuilder.ts
|
|
@@ -3626,6 +3890,7 @@ var DecryptForTxBuilder = class extends BaseBuilder {
|
|
|
3626
3890
|
permitHash;
|
|
3627
3891
|
permit;
|
|
3628
3892
|
permitSelection = "unset";
|
|
3893
|
+
pollCallback;
|
|
3629
3894
|
constructor(params) {
|
|
3630
3895
|
super({
|
|
3631
3896
|
config: params.config,
|
|
@@ -3651,6 +3916,10 @@ var DecryptForTxBuilder = class extends BaseBuilder {
|
|
|
3651
3916
|
getAccount() {
|
|
3652
3917
|
return this.account;
|
|
3653
3918
|
}
|
|
3919
|
+
onPoll(callback) {
|
|
3920
|
+
this.pollCallback = callback;
|
|
3921
|
+
return this;
|
|
3922
|
+
}
|
|
3654
3923
|
withPermit(permitOrPermitHash) {
|
|
3655
3924
|
if (this.permitSelection === "with-permit") {
|
|
3656
3925
|
throw new CofheError({
|
|
@@ -3778,7 +4047,13 @@ var DecryptForTxBuilder = class extends BaseBuilder {
|
|
|
3778
4047
|
this.assertPublicClient();
|
|
3779
4048
|
const thresholdNetworkUrl = await this.getThresholdNetworkUrl();
|
|
3780
4049
|
const permission = permit ? PermitUtils.getPermission(permit, true) : null;
|
|
3781
|
-
const { decryptedValue, signature } = await tnDecryptV2(
|
|
4050
|
+
const { decryptedValue, signature } = await tnDecryptV2({
|
|
4051
|
+
ctHash: this.ctHash,
|
|
4052
|
+
chainId: this.chainId,
|
|
4053
|
+
permission,
|
|
4054
|
+
thresholdNetworkUrl,
|
|
4055
|
+
onPoll: this.pollCallback
|
|
4056
|
+
});
|
|
3782
4057
|
return {
|
|
3783
4058
|
ctHash: this.ctHash,
|
|
3784
4059
|
decryptedValue,
|
|
@@ -3796,7 +4071,6 @@ var DecryptForTxBuilder = class extends BaseBuilder {
|
|
|
3796
4071
|
const permit = await this.getResolvedPermit();
|
|
3797
4072
|
if (permit !== null) {
|
|
3798
4073
|
PermitUtils.validate(permit);
|
|
3799
|
-
PermitUtils.isValid(permit);
|
|
3800
4074
|
const chainId = permit._signedDomain.chainId;
|
|
3801
4075
|
if (chainId === hardhat2.id) {
|
|
3802
4076
|
return await this.mocksDecryptForTx(permit);
|
|
@@ -3817,6 +4091,35 @@ var DecryptForTxBuilder = class extends BaseBuilder {
|
|
|
3817
4091
|
}
|
|
3818
4092
|
}
|
|
3819
4093
|
};
|
|
4094
|
+
var decryptResultSignerAbi = viem.parseAbi(["function decryptResultSigner() view returns (address)"]);
|
|
4095
|
+
var UINT_TYPE_MASK2 = 0x7fn;
|
|
4096
|
+
var TYPE_BYTE_OFFSET2 = 8n;
|
|
4097
|
+
var getEncryptionTypeFromCtHash2 = (ctHash) => Number(ctHash >> TYPE_BYTE_OFFSET2 & UINT_TYPE_MASK2);
|
|
4098
|
+
var buildDecryptResultHash = (ctHash, cleartext, chainId) => {
|
|
4099
|
+
const encryptionType = getEncryptionTypeFromCtHash2(ctHash);
|
|
4100
|
+
return viem.keccak256(
|
|
4101
|
+
viem.encodePacked(["uint256", "uint32", "uint64", "uint256"], [cleartext, encryptionType, BigInt(chainId), ctHash])
|
|
4102
|
+
);
|
|
4103
|
+
};
|
|
4104
|
+
async function verifyDecryptResult(handle, cleartext, signature, publicClient) {
|
|
4105
|
+
const chainId = publicClient.chain?.id ?? await publicClient.getChainId();
|
|
4106
|
+
const expectedSigner = await publicClient.readContract({
|
|
4107
|
+
address: TASK_MANAGER_ADDRESS,
|
|
4108
|
+
abi: decryptResultSignerAbi,
|
|
4109
|
+
functionName: "decryptResultSigner",
|
|
4110
|
+
args: []
|
|
4111
|
+
});
|
|
4112
|
+
if (viem.isAddressEqual(expectedSigner, viem.zeroAddress))
|
|
4113
|
+
return true;
|
|
4114
|
+
const ctHash = BigInt(handle);
|
|
4115
|
+
const messageHash = buildDecryptResultHash(ctHash, cleartext, chainId);
|
|
4116
|
+
try {
|
|
4117
|
+
const recovered = await viem.recoverAddress({ hash: messageHash, signature });
|
|
4118
|
+
return viem.isAddressEqual(recovered, expectedSigner);
|
|
4119
|
+
} catch {
|
|
4120
|
+
return false;
|
|
4121
|
+
}
|
|
4122
|
+
}
|
|
3820
4123
|
|
|
3821
4124
|
// core/client.ts
|
|
3822
4125
|
var InitialConnectStore = {
|
|
@@ -3935,6 +4238,11 @@ function createCofheClientBase(opts) {
|
|
|
3935
4238
|
requireConnected: _requireConnected
|
|
3936
4239
|
});
|
|
3937
4240
|
}
|
|
4241
|
+
function verifyDecryptResult2(handle, cleartext, signature) {
|
|
4242
|
+
_requireConnected();
|
|
4243
|
+
const { publicClient } = connectStore.getState();
|
|
4244
|
+
return verifyDecryptResult(handle, cleartext, signature, publicClient);
|
|
4245
|
+
}
|
|
3938
4246
|
const _getChainIdAndAccount = (chainId, account) => {
|
|
3939
4247
|
const state = connectStore.getState();
|
|
3940
4248
|
const _chainId = chainId ?? state.chainId;
|
|
@@ -4017,6 +4325,7 @@ function createCofheClientBase(opts) {
|
|
|
4017
4325
|
},
|
|
4018
4326
|
// Utils (no context needed)
|
|
4019
4327
|
getHash: permits.getHash,
|
|
4328
|
+
export: permits.export,
|
|
4020
4329
|
serialize: permits.serialize,
|
|
4021
4330
|
deserialize: permits.deserialize
|
|
4022
4331
|
};
|
|
@@ -4045,6 +4354,7 @@ function createCofheClientBase(opts) {
|
|
|
4045
4354
|
*/
|
|
4046
4355
|
decryptHandle: decryptForView,
|
|
4047
4356
|
decryptForTx,
|
|
4357
|
+
verifyDecryptResult: verifyDecryptResult2,
|
|
4048
4358
|
permits: clientPermits
|
|
4049
4359
|
// Add SDK-specific methods below that require connection
|
|
4050
4360
|
// Example:
|
|
@@ -4054,12 +4364,19 @@ function createCofheClientBase(opts) {
|
|
|
4054
4364
|
// },
|
|
4055
4365
|
};
|
|
4056
4366
|
}
|
|
4057
|
-
|
|
4367
|
+
|
|
4368
|
+
// web/const.ts
|
|
4369
|
+
var hasDOM = typeof globalThis?.document !== "undefined" && typeof globalThis?.window !== "undefined";
|
|
4370
|
+
|
|
4371
|
+
// web/storage.ts
|
|
4372
|
+
var createWebStorage = (opts = { enableLog: false }) => {
|
|
4373
|
+
if (!hasDOM)
|
|
4374
|
+
throw new Error("createWebStorage can only be used in a browser environment");
|
|
4058
4375
|
const client = iframeSharedStorage.constructClient({
|
|
4059
4376
|
iframe: {
|
|
4060
4377
|
src: "https://iframe-shared-storage.vercel.app/hub.html",
|
|
4061
4378
|
messagingOptions: {
|
|
4062
|
-
enableLog: "both"
|
|
4379
|
+
enableLog: opts.enableLog ? "both" : void 0
|
|
4063
4380
|
},
|
|
4064
4381
|
iframeReadyTimeoutMs: 3e4,
|
|
4065
4382
|
// if the iframe is not initied during this interval AND a reuqest is made, such request will throw an error
|
|
@@ -4082,6 +4399,16 @@ var createWebStorage = () => {
|
|
|
4082
4399
|
}
|
|
4083
4400
|
};
|
|
4084
4401
|
};
|
|
4402
|
+
function createSsrStorage() {
|
|
4403
|
+
console.warn("using no-op server-side SSR storage");
|
|
4404
|
+
return {
|
|
4405
|
+
getItem: async () => null,
|
|
4406
|
+
setItem: async () => {
|
|
4407
|
+
},
|
|
4408
|
+
removeItem: async () => {
|
|
4409
|
+
}
|
|
4410
|
+
};
|
|
4411
|
+
}
|
|
4085
4412
|
|
|
4086
4413
|
// web/workerManager.ts
|
|
4087
4414
|
var ZkProveWorkerManager = class {
|
|
@@ -4107,7 +4434,7 @@ var ZkProveWorkerManager = class {
|
|
|
4107
4434
|
return;
|
|
4108
4435
|
}
|
|
4109
4436
|
try {
|
|
4110
|
-
this.worker = new Worker(new URL("./zkProve.worker.js", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('out.js', document.baseURI).href))), { type: "module" });
|
|
4437
|
+
this.worker = new Worker(new URL("./zkProve.worker.js", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('out.js', document.baseURI).href))), { type: "module" });
|
|
4111
4438
|
} catch (error) {
|
|
4112
4439
|
reject(new Error(`Failed to create worker: ${error}`));
|
|
4113
4440
|
return;
|
|
@@ -4221,15 +4548,25 @@ function terminateWorker() {
|
|
|
4221
4548
|
function areWorkersAvailable() {
|
|
4222
4549
|
return typeof Worker !== "undefined";
|
|
4223
4550
|
}
|
|
4551
|
+
|
|
4552
|
+
// web/index.ts
|
|
4553
|
+
var tfheModule = null;
|
|
4224
4554
|
var tfheInitialized = false;
|
|
4225
4555
|
async function initTfhe() {
|
|
4226
4556
|
if (tfheInitialized)
|
|
4227
4557
|
return false;
|
|
4228
|
-
await
|
|
4229
|
-
await
|
|
4558
|
+
tfheModule = await import('tfhe');
|
|
4559
|
+
await tfheModule.default();
|
|
4560
|
+
await tfheModule.init_panic_hook();
|
|
4230
4561
|
tfheInitialized = true;
|
|
4231
4562
|
return true;
|
|
4232
4563
|
}
|
|
4564
|
+
function requireTfhe() {
|
|
4565
|
+
if (!tfheModule) {
|
|
4566
|
+
throw new Error("TFHE not initialized \u2014 call initTfhe() (or any client method that triggers it) first");
|
|
4567
|
+
}
|
|
4568
|
+
return tfheModule;
|
|
4569
|
+
}
|
|
4233
4570
|
var fromHexString2 = (hexString) => {
|
|
4234
4571
|
const cleanString = hexString.length % 2 === 1 ? `0${hexString}` : hexString;
|
|
4235
4572
|
const arr = cleanString.replace(/^0x/, "").match(/.{1,2}/g);
|
|
@@ -4237,16 +4574,25 @@ var fromHexString2 = (hexString) => {
|
|
|
4237
4574
|
return new Uint8Array();
|
|
4238
4575
|
return new Uint8Array(arr.map((byte) => parseInt(byte, 16)));
|
|
4239
4576
|
};
|
|
4577
|
+
var _deserializeTfhePublicKey = (buff) => {
|
|
4578
|
+
return requireTfhe().TfheCompactPublicKey.safe_deserialize(
|
|
4579
|
+
fromHexString2(buff),
|
|
4580
|
+
TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT
|
|
4581
|
+
);
|
|
4582
|
+
};
|
|
4583
|
+
var _deserializeCompactPkeCrs = (buff) => {
|
|
4584
|
+
return requireTfhe().CompactPkeCrs.safe_deserialize(fromHexString2(buff), TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
|
|
4585
|
+
};
|
|
4240
4586
|
var tfhePublicKeyDeserializer = (buff) => {
|
|
4241
|
-
|
|
4587
|
+
_deserializeTfhePublicKey(buff);
|
|
4242
4588
|
};
|
|
4243
4589
|
var compactPkeCrsDeserializer = (buff) => {
|
|
4244
|
-
|
|
4590
|
+
_deserializeCompactPkeCrs(buff);
|
|
4245
4591
|
};
|
|
4246
4592
|
var zkBuilderAndCrsGenerator = (fhe, crs) => {
|
|
4247
|
-
const fhePublicKey =
|
|
4248
|
-
const zkBuilder =
|
|
4249
|
-
const zkCrs =
|
|
4593
|
+
const fhePublicKey = _deserializeTfhePublicKey(fhe);
|
|
4594
|
+
const zkBuilder = requireTfhe().ProvenCompactCiphertextList.builder(fhePublicKey);
|
|
4595
|
+
const zkCrs = _deserializeCompactPkeCrs(crs);
|
|
4250
4596
|
return { zkBuilder, zkCrs };
|
|
4251
4597
|
};
|
|
4252
4598
|
async function zkProveWithWorker2(fheKeyHex, crsHex, items, metadata) {
|
|
@@ -4261,7 +4607,7 @@ function createCofheConfig(config) {
|
|
|
4261
4607
|
return createCofheConfigBase({
|
|
4262
4608
|
environment: "web",
|
|
4263
4609
|
...config,
|
|
4264
|
-
fheKeyStorage: config.fheKeyStorage === null ? null : config.fheKeyStorage ?? createWebStorage()
|
|
4610
|
+
fheKeyStorage: config.fheKeyStorage === null ? null : config.fheKeyStorage ?? (hasDOM ? createWebStorage() : createSsrStorage())
|
|
4265
4611
|
});
|
|
4266
4612
|
}
|
|
4267
4613
|
function createCofheClient(config) {
|
|
@@ -4291,4 +4637,6 @@ exports.areWorkersAvailable = areWorkersAvailable;
|
|
|
4291
4637
|
exports.createCofheClient = createCofheClient;
|
|
4292
4638
|
exports.createCofheClientWithCustomWorker = createCofheClientWithCustomWorker;
|
|
4293
4639
|
exports.createCofheConfig = createCofheConfig;
|
|
4640
|
+
exports.createSsrStorage = createSsrStorage;
|
|
4641
|
+
exports.hasDOM = hasDOM;
|
|
4294
4642
|
exports.terminateWorker = terminateWorker;
|