@cofhe/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.
- 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 +15 -5
- package/core/clientTypes.ts +7 -5
- package/core/consts.ts +9 -0
- package/core/decrypt/cofheMocksDecryptForTx.ts +14 -3
- package/core/decrypt/decryptForTxBuilder.ts +24 -10
- package/core/decrypt/decryptForViewBuilder.ts +14 -7
- package/core/decrypt/polling.ts +14 -0
- package/core/decrypt/tnDecryptUtils.ts +65 -0
- package/core/decrypt/{tnDecrypt.ts → tnDecryptV1.ts} +7 -70
- package/core/decrypt/tnDecryptV2.ts +483 -0
- 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 +8 -3
- 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 +21 -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-LWMRB6SD.js → chunk-S7OKGLFD.js} +615 -198
- package/dist/{clientTypes-Y43CKbOz.d.cts → clientTypes-BSbwairE.d.cts} +38 -13
- package/dist/{clientTypes-PQha8zes.d.ts → clientTypes-DDmcgZ0a.d.ts} +38 -13
- package/dist/core.cjs +691 -235
- package/dist/core.d.cts +24 -6
- package/dist/core.d.ts +24 -6
- package/dist/core.js +3 -2
- package/dist/node.cjs +696 -237
- 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.ts → permit-DnVMDT5h.d.cts} +34 -4
- package/dist/{permit-MZ502UBl.d.cts → 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 +718 -242
- package/dist/web.d.cts +8 -4
- package/dist/web.d.ts +8 -4
- package/dist/web.js +34 -11
- package/dist/zkProve.worker.cjs +6 -3
- package/dist/zkProve.worker.js +5 -3
- 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 +20 -6
- 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 +4 -3
- 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
|
@@ -14,25 +14,7 @@ var init = require('tfhe');
|
|
|
14
14
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
15
15
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
16
16
|
|
|
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);
|
|
17
|
+
var nacl__default = /*#__PURE__*/_interopDefault(nacl);
|
|
36
18
|
var init__default = /*#__PURE__*/_interopDefault(init);
|
|
37
19
|
|
|
38
20
|
// core/client.ts
|
|
@@ -126,6 +108,16 @@ var bigintSafeJsonStringify = (value) => {
|
|
|
126
108
|
};
|
|
127
109
|
var isCofheError = (error) => error instanceof CofheError;
|
|
128
110
|
|
|
111
|
+
// core/consts.ts
|
|
112
|
+
var TASK_MANAGER_ADDRESS = "0xeA30c4B8b44078Bbf8a6ef5b9f1eC1626C7848D9";
|
|
113
|
+
var MOCKS_ZK_VERIFIER_ADDRESS = "0x0000000000000000000000000000000000005001";
|
|
114
|
+
var MOCKS_THRESHOLD_NETWORK_ADDRESS = "0x0000000000000000000000000000000000005002";
|
|
115
|
+
var MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY = "0x6C8D7F768A6BB4AAFE85E8A2F5A9680355239C7E14646ED62B044E39DE154512";
|
|
116
|
+
var MOCKS_DECRYPT_RESULT_SIGNER_PRIVATE_KEY = "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d";
|
|
117
|
+
var TFHE_RS_ZK_MAX_BITS = 2048;
|
|
118
|
+
var TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT = BigInt(1 << 30);
|
|
119
|
+
var TFHE_RS_KEY_VERSION = 2;
|
|
120
|
+
|
|
129
121
|
// core/types.ts
|
|
130
122
|
var FheUintUTypes = [
|
|
131
123
|
2 /* Uint8 */,
|
|
@@ -248,7 +240,6 @@ var MAX_UINT32 = 4294967295n;
|
|
|
248
240
|
var MAX_UINT64 = 18446744073709551615n;
|
|
249
241
|
var MAX_UINT128 = 340282366920938463463374607431768211455n;
|
|
250
242
|
var MAX_UINT160 = 1461501637330902918203684832716283019655932542975n;
|
|
251
|
-
var MAX_ENCRYPTABLE_BITS = 2048;
|
|
252
243
|
var zkPack = (items, builder) => {
|
|
253
244
|
let totalBits = 0;
|
|
254
245
|
for (const item of items) {
|
|
@@ -312,14 +303,14 @@ var zkPack = (items, builder) => {
|
|
|
312
303
|
}
|
|
313
304
|
}
|
|
314
305
|
}
|
|
315
|
-
if (totalBits >
|
|
306
|
+
if (totalBits > TFHE_RS_ZK_MAX_BITS) {
|
|
316
307
|
throw new CofheError({
|
|
317
308
|
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 ${
|
|
309
|
+
message: `Total bits ${totalBits} exceeds ${TFHE_RS_ZK_MAX_BITS}`,
|
|
310
|
+
hint: `Ensure that the total bits of the items to encrypt does not exceed ${TFHE_RS_ZK_MAX_BITS}`,
|
|
320
311
|
context: {
|
|
321
312
|
totalBits,
|
|
322
|
-
maxBits:
|
|
313
|
+
maxBits: TFHE_RS_ZK_MAX_BITS,
|
|
323
314
|
items
|
|
324
315
|
}
|
|
325
316
|
});
|
|
@@ -338,7 +329,7 @@ var zkProve = async (builder, crs, metadata) => {
|
|
|
338
329
|
1
|
|
339
330
|
// ZkComputeLoad.Verify
|
|
340
331
|
);
|
|
341
|
-
resolve(compactList.
|
|
332
|
+
resolve(compactList.safe_serialize(TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT));
|
|
342
333
|
}, 0);
|
|
343
334
|
});
|
|
344
335
|
};
|
|
@@ -514,15 +505,6 @@ var MockZkVerifierAbi = [
|
|
|
514
505
|
},
|
|
515
506
|
{ type: "error", name: "InvalidInputs", inputs: [] }
|
|
516
507
|
];
|
|
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
508
|
function createMockZkVerifierSigner() {
|
|
527
509
|
return viem.createWalletClient({
|
|
528
510
|
chain: chains.hardhat,
|
|
@@ -564,14 +546,14 @@ async function cofheMocksCheckEncryptableBits(items) {
|
|
|
564
546
|
}
|
|
565
547
|
}
|
|
566
548
|
}
|
|
567
|
-
if (totalBits >
|
|
549
|
+
if (totalBits > TFHE_RS_ZK_MAX_BITS) {
|
|
568
550
|
throw new CofheError({
|
|
569
551
|
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 ${
|
|
552
|
+
message: `Total bits ${totalBits} exceeds ${TFHE_RS_ZK_MAX_BITS}`,
|
|
553
|
+
hint: `Ensure that the total bits of the items to encrypt does not exceed ${TFHE_RS_ZK_MAX_BITS}`,
|
|
572
554
|
context: {
|
|
573
555
|
totalBits,
|
|
574
|
-
maxBits:
|
|
556
|
+
maxBits: TFHE_RS_ZK_MAX_BITS,
|
|
575
557
|
items
|
|
576
558
|
}
|
|
577
559
|
});
|
|
@@ -842,6 +824,7 @@ function getThresholdNetworkUrlOrThrow(config, chainId) {
|
|
|
842
824
|
}
|
|
843
825
|
return url;
|
|
844
826
|
}
|
|
827
|
+
var KEYSTORE_NAME = `cofhesdk-keys-v${TFHE_RS_KEY_VERSION}`;
|
|
845
828
|
function isValidPersistedState(state) {
|
|
846
829
|
if (state && typeof state === "object") {
|
|
847
830
|
if ("fhe" in state && "crs" in state) {
|
|
@@ -896,7 +879,7 @@ function createKeysStore(storage) {
|
|
|
896
879
|
};
|
|
897
880
|
const clearKeysStorage = async () => {
|
|
898
881
|
if (storage) {
|
|
899
|
-
await storage.removeItem(
|
|
882
|
+
await storage.removeItem(KEYSTORE_NAME);
|
|
900
883
|
}
|
|
901
884
|
};
|
|
902
885
|
const rehydrateKeysStore = async () => {
|
|
@@ -926,7 +909,7 @@ function createStoreWithPersit(storage) {
|
|
|
926
909
|
if (_error)
|
|
927
910
|
throw new Error(`onRehydrateStorage: Error rehydrating keys store: ${_error}`);
|
|
928
911
|
},
|
|
929
|
-
name:
|
|
912
|
+
name: KEYSTORE_NAME,
|
|
930
913
|
storage: middleware.createJSONStorage(() => storage),
|
|
931
914
|
merge: (persistedState, currentState) => {
|
|
932
915
|
const persisted = isValidPersistedState(persistedState) ? persistedState : DEFAULT_KEYS_STORE;
|
|
@@ -1651,7 +1634,7 @@ var SealingKey = class _SealingKey {
|
|
|
1651
1634
|
const ephemPublicKey = parsedData.public_key instanceof Uint8Array ? parsedData.public_key : new Uint8Array(parsedData.public_key);
|
|
1652
1635
|
const dataToDecrypt = parsedData.data instanceof Uint8Array ? parsedData.data : new Uint8Array(parsedData.data);
|
|
1653
1636
|
const privateKeyBytes = fromHexString(this.privateKey);
|
|
1654
|
-
const decryptedMessage =
|
|
1637
|
+
const decryptedMessage = nacl__default.default.box.open(dataToDecrypt, nonce, ephemPublicKey, privateKeyBytes);
|
|
1655
1638
|
if (!decryptedMessage) {
|
|
1656
1639
|
throw new Error("Failed to decrypt message");
|
|
1657
1640
|
}
|
|
@@ -1684,9 +1667,9 @@ var SealingKey = class _SealingKey {
|
|
|
1684
1667
|
static seal = (value, publicKey) => {
|
|
1685
1668
|
isString(publicKey);
|
|
1686
1669
|
isBigIntOrNumber(value);
|
|
1687
|
-
const ephemeralKeyPair =
|
|
1688
|
-
const nonce =
|
|
1689
|
-
const encryptedMessage =
|
|
1670
|
+
const ephemeralKeyPair = nacl__default.default.box.keyPair();
|
|
1671
|
+
const nonce = nacl__default.default.randomBytes(nacl__default.default.box.nonceLength);
|
|
1672
|
+
const encryptedMessage = nacl__default.default.box(toBeArray(value), nonce, fromHexString(publicKey), ephemeralKeyPair.secretKey);
|
|
1690
1673
|
return {
|
|
1691
1674
|
data: encryptedMessage,
|
|
1692
1675
|
public_key: ephemeralKeyPair.publicKey,
|
|
@@ -1695,7 +1678,7 @@ var SealingKey = class _SealingKey {
|
|
|
1695
1678
|
};
|
|
1696
1679
|
};
|
|
1697
1680
|
var GenerateSealingKey = () => {
|
|
1698
|
-
const sodiumKeypair =
|
|
1681
|
+
const sodiumKeypair = nacl__default.default.box.keyPair();
|
|
1699
1682
|
return new SealingKey(toHexString2(sodiumKeypair.secretKey), toHexString2(sodiumKeypair.publicKey));
|
|
1700
1683
|
};
|
|
1701
1684
|
var SerializedSealingPair = zod.z.object({
|
|
@@ -1853,9 +1836,9 @@ var ValidationUtils = {
|
|
|
1853
1836
|
return false;
|
|
1854
1837
|
},
|
|
1855
1838
|
/**
|
|
1856
|
-
*
|
|
1839
|
+
* Checks that a permit is signed and not expired.
|
|
1857
1840
|
*/
|
|
1858
|
-
|
|
1841
|
+
isSignedAndNotExpired: (permit) => {
|
|
1859
1842
|
if (ValidationUtils.isExpired(permit)) {
|
|
1860
1843
|
return { valid: false, error: "expired" };
|
|
1861
1844
|
}
|
|
@@ -1863,6 +1846,34 @@ var ValidationUtils = {
|
|
|
1863
1846
|
return { valid: false, error: "not-signed" };
|
|
1864
1847
|
}
|
|
1865
1848
|
return { valid: true, error: null };
|
|
1849
|
+
},
|
|
1850
|
+
/**
|
|
1851
|
+
* Asserts that a permit is signed and not expired.
|
|
1852
|
+
*
|
|
1853
|
+
* Throws `Error` with message:
|
|
1854
|
+
* - `Permit is expired`
|
|
1855
|
+
* - `Permit is not signed`
|
|
1856
|
+
*/
|
|
1857
|
+
assertSignedAndNotExpired: (permit) => {
|
|
1858
|
+
const result = ValidationUtils.isSignedAndNotExpired(permit);
|
|
1859
|
+
if (result.valid)
|
|
1860
|
+
return;
|
|
1861
|
+
if (result.error === "expired") {
|
|
1862
|
+
throw new Error("Permit is expired");
|
|
1863
|
+
}
|
|
1864
|
+
if (result.error === "not-signed") {
|
|
1865
|
+
throw new Error("Permit is not signed");
|
|
1866
|
+
}
|
|
1867
|
+
throw new Error("Permit is invalid");
|
|
1868
|
+
},
|
|
1869
|
+
isValid: (permit) => {
|
|
1870
|
+
const schema = permit.type === "self" ? SelfPermitValidator : permit.type === "sharing" ? SharingPermitValidator : permit.type === "recipient" ? ImportPermitValidator : null;
|
|
1871
|
+
if (schema == null)
|
|
1872
|
+
return { valid: false, error: "invalid-schema" };
|
|
1873
|
+
const schemaResult = schema.safeParse(permit);
|
|
1874
|
+
if (!schemaResult.success)
|
|
1875
|
+
return { valid: false, error: "invalid-schema" };
|
|
1876
|
+
return ValidationUtils.isSignedAndNotExpired(permit);
|
|
1866
1877
|
}
|
|
1867
1878
|
};
|
|
1868
1879
|
|
|
@@ -2244,9 +2255,9 @@ var PermitUtils = {
|
|
|
2244
2255
|
};
|
|
2245
2256
|
},
|
|
2246
2257
|
/**
|
|
2247
|
-
* Validate a permit
|
|
2258
|
+
* Validate a permit (schema-level validation)
|
|
2248
2259
|
*/
|
|
2249
|
-
|
|
2260
|
+
validateSchema: (permit) => {
|
|
2250
2261
|
if (permit.type === "self") {
|
|
2251
2262
|
return validateSelfPermit(permit);
|
|
2252
2263
|
} else if (permit.type === "sharing") {
|
|
@@ -2257,12 +2268,27 @@ var PermitUtils = {
|
|
|
2257
2268
|
throw new Error("Invalid permit type");
|
|
2258
2269
|
}
|
|
2259
2270
|
},
|
|
2271
|
+
/**
|
|
2272
|
+
* Validate a permit (holistic validation).
|
|
2273
|
+
*
|
|
2274
|
+
* This validates:
|
|
2275
|
+
* - Permit schema (shape + invariants)
|
|
2276
|
+
* - Permit is signed
|
|
2277
|
+
* - Permit is not expired
|
|
2278
|
+
*
|
|
2279
|
+
* For schema-only validation, use `validateSchema(permit)`.
|
|
2280
|
+
*/
|
|
2281
|
+
validate: (permit) => {
|
|
2282
|
+
const validated = PermitUtils.validateSchema(permit);
|
|
2283
|
+
ValidationUtils.assertSignedAndNotExpired(validated);
|
|
2284
|
+
return validated;
|
|
2285
|
+
},
|
|
2260
2286
|
/**
|
|
2261
2287
|
* Get the permission object from a permit (for use in contracts)
|
|
2262
2288
|
*/
|
|
2263
2289
|
getPermission: (permit, skipValidation = false) => {
|
|
2264
2290
|
if (!skipValidation) {
|
|
2265
|
-
PermitUtils.
|
|
2291
|
+
PermitUtils.validateSchema(permit);
|
|
2266
2292
|
}
|
|
2267
2293
|
return {
|
|
2268
2294
|
issuer: permit.issuer,
|
|
@@ -2328,8 +2354,17 @@ var PermitUtils = {
|
|
|
2328
2354
|
return ValidationUtils.isSigned(permit);
|
|
2329
2355
|
},
|
|
2330
2356
|
/**
|
|
2331
|
-
* Check if permit is
|
|
2357
|
+
* Check if permit is signed and not expired
|
|
2358
|
+
*/
|
|
2359
|
+
isSignedAndNotExpired: (permit) => {
|
|
2360
|
+
return ValidationUtils.isSignedAndNotExpired(permit);
|
|
2361
|
+
},
|
|
2362
|
+
/**
|
|
2363
|
+
* Assert that permit is signed and not expired
|
|
2332
2364
|
*/
|
|
2365
|
+
assertSignedAndNotExpired: (permit) => {
|
|
2366
|
+
return ValidationUtils.assertSignedAndNotExpired(permit);
|
|
2367
|
+
},
|
|
2333
2368
|
isValid: (permit) => {
|
|
2334
2369
|
return ValidationUtils.isValid(permit);
|
|
2335
2370
|
},
|
|
@@ -2507,19 +2542,22 @@ var importShared = async (options, publicClient, walletClient) => {
|
|
|
2507
2542
|
var getHash = (permit) => {
|
|
2508
2543
|
return PermitUtils.getHash(permit);
|
|
2509
2544
|
};
|
|
2545
|
+
var exportShared = (permit) => {
|
|
2546
|
+
return PermitUtils.export(permit);
|
|
2547
|
+
};
|
|
2510
2548
|
var serialize = (permit) => {
|
|
2511
2549
|
return PermitUtils.serialize(permit);
|
|
2512
2550
|
};
|
|
2513
2551
|
var deserialize = (serialized) => {
|
|
2514
2552
|
return PermitUtils.deserialize(serialized);
|
|
2515
2553
|
};
|
|
2516
|
-
var getPermit2 =
|
|
2554
|
+
var getPermit2 = (chainId, account, hash) => {
|
|
2517
2555
|
return permitStore.getPermit(chainId, account, hash);
|
|
2518
2556
|
};
|
|
2519
|
-
var getPermits2 =
|
|
2557
|
+
var getPermits2 = (chainId, account) => {
|
|
2520
2558
|
return permitStore.getPermits(chainId, account);
|
|
2521
2559
|
};
|
|
2522
|
-
var getActivePermit2 =
|
|
2560
|
+
var getActivePermit2 = (chainId, account) => {
|
|
2523
2561
|
return permitStore.getActivePermit(chainId, account);
|
|
2524
2562
|
};
|
|
2525
2563
|
var getActivePermitHash2 = (chainId, account) => {
|
|
@@ -2557,6 +2595,7 @@ var permits = {
|
|
|
2557
2595
|
getOrCreateSelfPermit,
|
|
2558
2596
|
getOrCreateSharingPermit,
|
|
2559
2597
|
getHash,
|
|
2598
|
+
export: exportShared,
|
|
2560
2599
|
serialize,
|
|
2561
2600
|
deserialize,
|
|
2562
2601
|
getPermit: getPermit2,
|
|
@@ -2799,9 +2838,19 @@ async function cofheMocksDecryptForView(ctHash, utype, permit, publicClient) {
|
|
|
2799
2838
|
return unsealed;
|
|
2800
2839
|
}
|
|
2801
2840
|
|
|
2841
|
+
// core/decrypt/polling.ts
|
|
2842
|
+
function computeMinuteRampPollIntervalMs(elapsedMs, params) {
|
|
2843
|
+
const elapsedSeconds = Math.floor(elapsedMs / 1e3);
|
|
2844
|
+
const intervalSeconds = 1 + Math.floor(elapsedSeconds / 60);
|
|
2845
|
+
const intervalMs = intervalSeconds * 1e3;
|
|
2846
|
+
return Math.min(params.maxIntervalMs, Math.max(params.minIntervalMs, intervalMs));
|
|
2847
|
+
}
|
|
2848
|
+
|
|
2802
2849
|
// core/decrypt/tnSealOutputV2.ts
|
|
2803
2850
|
var POLL_INTERVAL_MS = 1e3;
|
|
2804
|
-
var
|
|
2851
|
+
var POLL_MAX_INTERVAL_MS = 1e4;
|
|
2852
|
+
var SEAL_OUTPUT_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
2853
|
+
var SUBMIT_RETRY_INTERVAL_MS = 1e3;
|
|
2805
2854
|
function numberArrayToUint8Array(arr) {
|
|
2806
2855
|
return new Uint8Array(arr);
|
|
2807
2856
|
}
|
|
@@ -2818,93 +2867,193 @@ function convertSealedData(sealed) {
|
|
|
2818
2867
|
nonce: numberArrayToUint8Array(sealed.nonce)
|
|
2819
2868
|
};
|
|
2820
2869
|
}
|
|
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
|
-
});
|
|
2870
|
+
function getSealedDataFromSubmitResponse(value) {
|
|
2871
|
+
if (value.sealed)
|
|
2872
|
+
return value.sealed;
|
|
2873
|
+
if (Array.isArray(value.sealed_data) && Array.isArray(value.ephemeral_public_key) && Array.isArray(value.nonce)) {
|
|
2874
|
+
return {
|
|
2875
|
+
data: value.sealed_data,
|
|
2876
|
+
public_key: value.ephemeral_public_key,
|
|
2877
|
+
nonce: value.nonce
|
|
2878
|
+
};
|
|
2847
2879
|
}
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
errorMessage = response.statusText || errorMessage;
|
|
2855
|
-
}
|
|
2880
|
+
return void 0;
|
|
2881
|
+
}
|
|
2882
|
+
function parseCompletedSealOutputResponse(params) {
|
|
2883
|
+
const { value, thresholdNetworkUrl, requestId } = params;
|
|
2884
|
+
if (value.is_succeed === false) {
|
|
2885
|
+
const errorMessage = value.error_message || "Unknown error";
|
|
2856
2886
|
throw new CofheError({
|
|
2857
2887
|
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
2858
2888
|
message: `sealOutput request failed: ${errorMessage}`,
|
|
2859
|
-
hint: "Check the threshold network URL and request parameters.",
|
|
2860
2889
|
context: {
|
|
2861
2890
|
thresholdNetworkUrl,
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
body
|
|
2891
|
+
requestId,
|
|
2892
|
+
response: value
|
|
2865
2893
|
}
|
|
2866
2894
|
});
|
|
2867
2895
|
}
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
submitResponse = await response.json();
|
|
2871
|
-
} catch (e) {
|
|
2896
|
+
const sealed = "sealed" in value ? value.sealed : getSealedDataFromSubmitResponse(value);
|
|
2897
|
+
if (!sealed) {
|
|
2872
2898
|
throw new CofheError({
|
|
2873
|
-
code: "
|
|
2874
|
-
message: `
|
|
2875
|
-
cause: e instanceof Error ? e : void 0,
|
|
2899
|
+
code: "SEAL_OUTPUT_RETURNED_NULL" /* SealOutputReturnedNull */,
|
|
2900
|
+
message: `sealOutput request completed but returned no sealed data`,
|
|
2876
2901
|
context: {
|
|
2877
2902
|
thresholdNetworkUrl,
|
|
2878
|
-
|
|
2903
|
+
requestId,
|
|
2904
|
+
response: value
|
|
2879
2905
|
}
|
|
2880
2906
|
});
|
|
2881
2907
|
}
|
|
2882
|
-
|
|
2908
|
+
return convertSealedData(sealed);
|
|
2909
|
+
}
|
|
2910
|
+
async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, permission, overallStartTime, onPoll) {
|
|
2911
|
+
const body = {
|
|
2912
|
+
ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
|
|
2913
|
+
host_chain_id: chainId,
|
|
2914
|
+
permit: permission
|
|
2915
|
+
};
|
|
2916
|
+
let attemptIndex = 0;
|
|
2917
|
+
for (; ; ) {
|
|
2918
|
+
let response;
|
|
2919
|
+
try {
|
|
2920
|
+
response = await fetch(`${thresholdNetworkUrl}/v2/sealoutput`, {
|
|
2921
|
+
method: "POST",
|
|
2922
|
+
headers: {
|
|
2923
|
+
"Content-Type": "application/json"
|
|
2924
|
+
},
|
|
2925
|
+
body: JSON.stringify(body)
|
|
2926
|
+
});
|
|
2927
|
+
} catch (e) {
|
|
2928
|
+
throw new CofheError({
|
|
2929
|
+
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
2930
|
+
message: `sealOutput request failed`,
|
|
2931
|
+
hint: "Ensure the threshold network URL is valid and reachable.",
|
|
2932
|
+
cause: e instanceof Error ? e : void 0,
|
|
2933
|
+
context: {
|
|
2934
|
+
thresholdNetworkUrl,
|
|
2935
|
+
body,
|
|
2936
|
+
attemptIndex
|
|
2937
|
+
}
|
|
2938
|
+
});
|
|
2939
|
+
}
|
|
2940
|
+
if (!response.ok) {
|
|
2941
|
+
let errorMessage = `HTTP ${response.status}`;
|
|
2942
|
+
try {
|
|
2943
|
+
const errorBody = await response.json();
|
|
2944
|
+
errorMessage = errorBody.error_message || errorBody.message || errorMessage;
|
|
2945
|
+
} catch {
|
|
2946
|
+
errorMessage = response.statusText || errorMessage;
|
|
2947
|
+
}
|
|
2948
|
+
throw new CofheError({
|
|
2949
|
+
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
2950
|
+
message: `sealOutput request failed: ${errorMessage}`,
|
|
2951
|
+
hint: "Check the threshold network URL and request parameters.",
|
|
2952
|
+
context: {
|
|
2953
|
+
thresholdNetworkUrl,
|
|
2954
|
+
status: response.status,
|
|
2955
|
+
statusText: response.statusText,
|
|
2956
|
+
body,
|
|
2957
|
+
attemptIndex
|
|
2958
|
+
}
|
|
2959
|
+
});
|
|
2960
|
+
}
|
|
2961
|
+
let submitResponse;
|
|
2962
|
+
if (response.status !== 204) {
|
|
2963
|
+
try {
|
|
2964
|
+
submitResponse = await response.json();
|
|
2965
|
+
} catch (e) {
|
|
2966
|
+
throw new CofheError({
|
|
2967
|
+
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
2968
|
+
message: `Failed to parse sealOutput submit response`,
|
|
2969
|
+
cause: e instanceof Error ? e : void 0,
|
|
2970
|
+
context: {
|
|
2971
|
+
thresholdNetworkUrl,
|
|
2972
|
+
body,
|
|
2973
|
+
attemptIndex
|
|
2974
|
+
}
|
|
2975
|
+
});
|
|
2976
|
+
}
|
|
2977
|
+
if (getSealedDataFromSubmitResponse(submitResponse)) {
|
|
2978
|
+
return {
|
|
2979
|
+
kind: "completed",
|
|
2980
|
+
sealed: parseCompletedSealOutputResponse({
|
|
2981
|
+
value: submitResponse,
|
|
2982
|
+
thresholdNetworkUrl,
|
|
2983
|
+
requestId: submitResponse.request_id
|
|
2984
|
+
})
|
|
2985
|
+
};
|
|
2986
|
+
}
|
|
2987
|
+
if (submitResponse.request_id) {
|
|
2988
|
+
return { kind: "request_id", requestId: submitResponse.request_id };
|
|
2989
|
+
}
|
|
2990
|
+
}
|
|
2991
|
+
if (response.status === 204) {
|
|
2992
|
+
const elapsedMs = Date.now() - overallStartTime;
|
|
2993
|
+
if (elapsedMs > SEAL_OUTPUT_TIMEOUT_MS) {
|
|
2994
|
+
throw new CofheError({
|
|
2995
|
+
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
2996
|
+
message: `sealOutput submit retried without receiving request_id for ${SEAL_OUTPUT_TIMEOUT_MS}ms`,
|
|
2997
|
+
hint: "The ciphertext may still be propagating. Try again later.",
|
|
2998
|
+
context: {
|
|
2999
|
+
thresholdNetworkUrl,
|
|
3000
|
+
body,
|
|
3001
|
+
attemptIndex,
|
|
3002
|
+
timeoutMs: SEAL_OUTPUT_TIMEOUT_MS,
|
|
3003
|
+
submitResponse,
|
|
3004
|
+
status: response.status
|
|
3005
|
+
}
|
|
3006
|
+
});
|
|
3007
|
+
}
|
|
3008
|
+
onPoll?.({
|
|
3009
|
+
operation: "sealoutput",
|
|
3010
|
+
requestId: "",
|
|
3011
|
+
attemptIndex,
|
|
3012
|
+
elapsedMs,
|
|
3013
|
+
intervalMs: SUBMIT_RETRY_INTERVAL_MS,
|
|
3014
|
+
timeoutMs: SEAL_OUTPUT_TIMEOUT_MS
|
|
3015
|
+
});
|
|
3016
|
+
await new Promise((resolve) => setTimeout(resolve, SUBMIT_RETRY_INTERVAL_MS));
|
|
3017
|
+
attemptIndex += 1;
|
|
3018
|
+
continue;
|
|
3019
|
+
}
|
|
2883
3020
|
throw new CofheError({
|
|
2884
3021
|
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
2885
3022
|
message: `sealOutput submit response missing request_id`,
|
|
2886
3023
|
context: {
|
|
2887
3024
|
thresholdNetworkUrl,
|
|
2888
3025
|
body,
|
|
2889
|
-
submitResponse
|
|
3026
|
+
submitResponse,
|
|
3027
|
+
attemptIndex
|
|
2890
3028
|
}
|
|
2891
3029
|
});
|
|
2892
3030
|
}
|
|
2893
|
-
return submitResponse.request_id;
|
|
2894
3031
|
}
|
|
2895
|
-
async function pollSealOutputStatus(thresholdNetworkUrl, requestId) {
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
3032
|
+
async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStartTime, onPoll) {
|
|
3033
|
+
let attemptIndex = 0;
|
|
3034
|
+
while (true) {
|
|
3035
|
+
const elapsedMs = Date.now() - overallStartTime;
|
|
3036
|
+
const intervalMs = computeMinuteRampPollIntervalMs(elapsedMs, {
|
|
3037
|
+
minIntervalMs: POLL_INTERVAL_MS,
|
|
3038
|
+
maxIntervalMs: POLL_MAX_INTERVAL_MS
|
|
3039
|
+
});
|
|
3040
|
+
onPoll?.({
|
|
3041
|
+
operation: "sealoutput",
|
|
3042
|
+
requestId,
|
|
3043
|
+
attemptIndex,
|
|
3044
|
+
elapsedMs,
|
|
3045
|
+
intervalMs,
|
|
3046
|
+
timeoutMs: SEAL_OUTPUT_TIMEOUT_MS
|
|
3047
|
+
});
|
|
3048
|
+
if (elapsedMs > SEAL_OUTPUT_TIMEOUT_MS) {
|
|
2900
3049
|
throw new CofheError({
|
|
2901
3050
|
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
2902
|
-
message: `sealOutput polling timed out after ${
|
|
3051
|
+
message: `sealOutput polling timed out after ${SEAL_OUTPUT_TIMEOUT_MS}ms`,
|
|
2903
3052
|
hint: "The request may still be processing. Try again later.",
|
|
2904
3053
|
context: {
|
|
2905
3054
|
thresholdNetworkUrl,
|
|
2906
3055
|
requestId,
|
|
2907
|
-
timeoutMs:
|
|
3056
|
+
timeoutMs: SEAL_OUTPUT_TIMEOUT_MS
|
|
2908
3057
|
}
|
|
2909
3058
|
});
|
|
2910
3059
|
}
|
|
@@ -2973,32 +3122,14 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId) {
|
|
|
2973
3122
|
});
|
|
2974
3123
|
}
|
|
2975
3124
|
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);
|
|
3125
|
+
return parseCompletedSealOutputResponse({
|
|
3126
|
+
value: statusResponse,
|
|
3127
|
+
thresholdNetworkUrl,
|
|
3128
|
+
requestId
|
|
3129
|
+
});
|
|
3000
3130
|
}
|
|
3001
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
3131
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
3132
|
+
attemptIndex += 1;
|
|
3002
3133
|
}
|
|
3003
3134
|
throw new CofheError({
|
|
3004
3135
|
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
@@ -3009,9 +3140,21 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId) {
|
|
|
3009
3140
|
}
|
|
3010
3141
|
});
|
|
3011
3142
|
}
|
|
3012
|
-
async function tnSealOutputV2(
|
|
3013
|
-
const
|
|
3014
|
-
|
|
3143
|
+
async function tnSealOutputV2(params) {
|
|
3144
|
+
const { thresholdNetworkUrl, ctHash, chainId, permission, onPoll } = params;
|
|
3145
|
+
const overallStartTime = Date.now();
|
|
3146
|
+
const submitResult = await submitSealOutputRequest(
|
|
3147
|
+
thresholdNetworkUrl,
|
|
3148
|
+
ctHash,
|
|
3149
|
+
chainId,
|
|
3150
|
+
permission,
|
|
3151
|
+
overallStartTime,
|
|
3152
|
+
onPoll
|
|
3153
|
+
);
|
|
3154
|
+
if (submitResult.kind === "completed") {
|
|
3155
|
+
return submitResult.sealed;
|
|
3156
|
+
}
|
|
3157
|
+
return await pollSealOutputStatus(thresholdNetworkUrl, submitResult.requestId, overallStartTime, onPoll);
|
|
3015
3158
|
}
|
|
3016
3159
|
|
|
3017
3160
|
// core/decrypt/decryptForViewBuilder.ts
|
|
@@ -3020,6 +3163,7 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3020
3163
|
utype;
|
|
3021
3164
|
permitHash;
|
|
3022
3165
|
permit;
|
|
3166
|
+
pollCallback;
|
|
3023
3167
|
constructor(params) {
|
|
3024
3168
|
super({
|
|
3025
3169
|
config: params.config,
|
|
@@ -3076,6 +3220,10 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3076
3220
|
getAccount() {
|
|
3077
3221
|
return this.account;
|
|
3078
3222
|
}
|
|
3223
|
+
onPoll(callback) {
|
|
3224
|
+
this.pollCallback = callback;
|
|
3225
|
+
return this;
|
|
3226
|
+
}
|
|
3079
3227
|
withPermit(permitOrPermitHash) {
|
|
3080
3228
|
if (typeof permitOrPermitHash === "string") {
|
|
3081
3229
|
this.permitHash = permitOrPermitHash;
|
|
@@ -3199,7 +3347,13 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3199
3347
|
this.assertPublicClient();
|
|
3200
3348
|
const thresholdNetworkUrl = await this.getThresholdNetworkUrl();
|
|
3201
3349
|
const permission = PermitUtils.getPermission(permit, true);
|
|
3202
|
-
const sealed = await tnSealOutputV2(
|
|
3350
|
+
const sealed = await tnSealOutputV2({
|
|
3351
|
+
ctHash: this.ctHash,
|
|
3352
|
+
chainId: this.chainId,
|
|
3353
|
+
permission,
|
|
3354
|
+
thresholdNetworkUrl,
|
|
3355
|
+
onPoll: this.pollCallback
|
|
3356
|
+
});
|
|
3203
3357
|
return PermitUtils.unseal(permit, sealed);
|
|
3204
3358
|
}
|
|
3205
3359
|
/**
|
|
@@ -3227,7 +3381,6 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3227
3381
|
this.validateUtypeOrThrow();
|
|
3228
3382
|
const permit = await this.getResolvedPermit();
|
|
3229
3383
|
PermitUtils.validate(permit);
|
|
3230
|
-
PermitUtils.isValid(permit);
|
|
3231
3384
|
const chainId = permit._signedDomain.chainId;
|
|
3232
3385
|
let unsealed;
|
|
3233
3386
|
if (chainId === hardhat2.id) {
|
|
@@ -3238,6 +3391,9 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3238
3391
|
return convertViaUtype(this.utype, unsealed);
|
|
3239
3392
|
}
|
|
3240
3393
|
};
|
|
3394
|
+
var UINT_TYPE_MASK = 0x7fn;
|
|
3395
|
+
var TYPE_BYTE_OFFSET = 8n;
|
|
3396
|
+
var getEncryptionTypeFromCtHash = (ctHash) => Number(ctHash >> TYPE_BYTE_OFFSET & UINT_TYPE_MASK);
|
|
3241
3397
|
async function cofheMocksDecryptForTx(ctHash, utype, permit, publicClient) {
|
|
3242
3398
|
let allowed;
|
|
3243
3399
|
let error;
|
|
@@ -3275,7 +3431,13 @@ async function cofheMocksDecryptForTx(ctHash, utype, permit, publicClient) {
|
|
|
3275
3431
|
message: `mocks decryptForTx call failed: ACL Access Denied (NotAllowed)`
|
|
3276
3432
|
});
|
|
3277
3433
|
}
|
|
3278
|
-
const
|
|
3434
|
+
const chainId = publicClient.chain?.id ?? await publicClient.getChainId();
|
|
3435
|
+
const normalizedCtHash = BigInt(ctHash);
|
|
3436
|
+
const encryptionType = getEncryptionTypeFromCtHash(normalizedCtHash);
|
|
3437
|
+
const packed = viem.encodePacked(
|
|
3438
|
+
["uint256", "uint32", "uint64", "uint256"],
|
|
3439
|
+
[decryptedValue, encryptionType, BigInt(chainId), normalizedCtHash]
|
|
3440
|
+
);
|
|
3279
3441
|
const messageHash = viem.keccak256(packed);
|
|
3280
3442
|
const signature = await accounts.sign({
|
|
3281
3443
|
hash: messageHash,
|
|
@@ -3288,7 +3450,7 @@ async function cofheMocksDecryptForTx(ctHash, utype, permit, publicClient) {
|
|
|
3288
3450
|
signature
|
|
3289
3451
|
};
|
|
3290
3452
|
}
|
|
3291
|
-
function
|
|
3453
|
+
function normalizeTnSignature(signature) {
|
|
3292
3454
|
if (typeof signature !== "string") {
|
|
3293
3455
|
throw new CofheError({
|
|
3294
3456
|
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
@@ -3344,141 +3506,384 @@ function parseDecryptedBytesToBigInt(decrypted) {
|
|
|
3344
3506
|
}
|
|
3345
3507
|
return BigInt(`0x${hex}`);
|
|
3346
3508
|
}
|
|
3347
|
-
|
|
3509
|
+
|
|
3510
|
+
// core/decrypt/tnDecryptV2.ts
|
|
3511
|
+
var POLL_INTERVAL_MS2 = 1e3;
|
|
3512
|
+
var POLL_MAX_INTERVAL_MS2 = 1e4;
|
|
3513
|
+
var DECRYPT_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
3514
|
+
var SUBMIT_RETRY_INTERVAL_MS2 = 1e3;
|
|
3515
|
+
function assertDecryptSubmitResponseV2(value) {
|
|
3348
3516
|
if (value == null || typeof value !== "object") {
|
|
3349
3517
|
throw new CofheError({
|
|
3350
3518
|
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3351
|
-
message: "decrypt response must be a JSON object",
|
|
3519
|
+
message: "decrypt submit response must be a JSON object",
|
|
3352
3520
|
context: {
|
|
3353
3521
|
value
|
|
3354
3522
|
}
|
|
3355
3523
|
});
|
|
3356
3524
|
}
|
|
3357
3525
|
const v = value;
|
|
3358
|
-
|
|
3359
|
-
const signature = v.signature;
|
|
3360
|
-
const encryptionType = v.encryption_type;
|
|
3361
|
-
const errorMessage = v.error_message;
|
|
3362
|
-
if (!Array.isArray(decrypted)) {
|
|
3526
|
+
if (v.request_id !== null && typeof v.request_id !== "string") {
|
|
3363
3527
|
throw new CofheError({
|
|
3364
|
-
code: "
|
|
3365
|
-
message: "decrypt response
|
|
3366
|
-
context: {
|
|
3528
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3529
|
+
message: "decrypt submit response has invalid request_id",
|
|
3530
|
+
context: {
|
|
3531
|
+
value
|
|
3532
|
+
}
|
|
3367
3533
|
});
|
|
3368
3534
|
}
|
|
3369
|
-
|
|
3535
|
+
return {
|
|
3536
|
+
request_id: v.request_id ?? null,
|
|
3537
|
+
status: typeof v.status === "string" ? v.status : void 0,
|
|
3538
|
+
is_succeed: typeof v.is_succeed === "boolean" ? v.is_succeed : void 0,
|
|
3539
|
+
decrypted: Array.isArray(v.decrypted) ? v.decrypted : void 0,
|
|
3540
|
+
signature: typeof v.signature === "string" ? v.signature : void 0,
|
|
3541
|
+
encryption_type: typeof v.encryption_type === "number" ? v.encryption_type : void 0,
|
|
3542
|
+
error_message: typeof v.error_message === "string" || v.error_message === null ? v.error_message : void 0,
|
|
3543
|
+
message: typeof v.message === "string" ? v.message : void 0
|
|
3544
|
+
};
|
|
3545
|
+
}
|
|
3546
|
+
function parseCompletedDecryptResponseV2(params) {
|
|
3547
|
+
const { value, thresholdNetworkUrl, requestId } = params;
|
|
3548
|
+
if (value.is_succeed === false) {
|
|
3549
|
+
const errorMessage = value.error_message || "Unknown error";
|
|
3370
3550
|
throw new CofheError({
|
|
3371
|
-
code: "
|
|
3372
|
-
message:
|
|
3373
|
-
context: {
|
|
3551
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3552
|
+
message: `decrypt request failed: ${errorMessage}`,
|
|
3553
|
+
context: {
|
|
3554
|
+
thresholdNetworkUrl,
|
|
3555
|
+
requestId,
|
|
3556
|
+
response: value
|
|
3557
|
+
}
|
|
3374
3558
|
});
|
|
3375
3559
|
}
|
|
3376
|
-
if (
|
|
3560
|
+
if (value.error_message) {
|
|
3377
3561
|
throw new CofheError({
|
|
3378
3562
|
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3379
|
-
message:
|
|
3380
|
-
context: {
|
|
3563
|
+
message: `decrypt request failed: ${value.error_message}`,
|
|
3564
|
+
context: {
|
|
3565
|
+
thresholdNetworkUrl,
|
|
3566
|
+
requestId,
|
|
3567
|
+
response: value
|
|
3568
|
+
}
|
|
3381
3569
|
});
|
|
3382
3570
|
}
|
|
3383
|
-
if (!(
|
|
3571
|
+
if (!Array.isArray(value.decrypted)) {
|
|
3384
3572
|
throw new CofheError({
|
|
3385
|
-
code: "
|
|
3386
|
-
message: "decrypt response
|
|
3387
|
-
context: {
|
|
3573
|
+
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3574
|
+
message: "decrypt completed but response missing <decrypted> byte array",
|
|
3575
|
+
context: {
|
|
3576
|
+
thresholdNetworkUrl,
|
|
3577
|
+
requestId,
|
|
3578
|
+
response: value
|
|
3579
|
+
}
|
|
3388
3580
|
});
|
|
3389
3581
|
}
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
encryption_type: encryptionType,
|
|
3394
|
-
error_message: errorMessage
|
|
3395
|
-
};
|
|
3582
|
+
const decryptedValue = parseDecryptedBytesToBigInt(value.decrypted);
|
|
3583
|
+
const signature = normalizeTnSignature(value.signature);
|
|
3584
|
+
return { decryptedValue, signature };
|
|
3396
3585
|
}
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
let response;
|
|
3406
|
-
try {
|
|
3407
|
-
response = await fetch(`${thresholdNetworkUrl}/decrypt`, {
|
|
3408
|
-
method: "POST",
|
|
3409
|
-
headers: {
|
|
3410
|
-
"Content-Type": "application/json"
|
|
3411
|
-
},
|
|
3412
|
-
body: JSON.stringify(body)
|
|
3586
|
+
function assertDecryptStatusResponseV2(value) {
|
|
3587
|
+
if (value == null || typeof value !== "object") {
|
|
3588
|
+
throw new CofheError({
|
|
3589
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3590
|
+
message: "decrypt status response must be a JSON object",
|
|
3591
|
+
context: {
|
|
3592
|
+
value
|
|
3593
|
+
}
|
|
3413
3594
|
});
|
|
3414
|
-
}
|
|
3595
|
+
}
|
|
3596
|
+
const v = value;
|
|
3597
|
+
const requestId = v.request_id;
|
|
3598
|
+
const status = v.status;
|
|
3599
|
+
const submittedAt = v.submitted_at;
|
|
3600
|
+
if (typeof requestId !== "string" || requestId.trim().length === 0) {
|
|
3415
3601
|
throw new CofheError({
|
|
3416
3602
|
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3417
|
-
message:
|
|
3418
|
-
hint: "Ensure the threshold network URL is valid and reachable.",
|
|
3419
|
-
cause: e instanceof Error ? e : void 0,
|
|
3603
|
+
message: "decrypt status response missing request_id",
|
|
3420
3604
|
context: {
|
|
3421
|
-
|
|
3422
|
-
body
|
|
3605
|
+
value
|
|
3423
3606
|
}
|
|
3424
3607
|
});
|
|
3425
3608
|
}
|
|
3426
|
-
|
|
3427
|
-
if (!response.ok) {
|
|
3428
|
-
let errorMessage = response.statusText || `HTTP ${response.status}`;
|
|
3429
|
-
try {
|
|
3430
|
-
const errorBody = JSON.parse(responseText);
|
|
3431
|
-
const maybeMessage = errorBody.error_message || errorBody.message;
|
|
3432
|
-
if (typeof maybeMessage === "string" && maybeMessage.length > 0)
|
|
3433
|
-
errorMessage = maybeMessage;
|
|
3434
|
-
} catch {
|
|
3435
|
-
const trimmed = responseText.trim();
|
|
3436
|
-
if (trimmed.length > 0)
|
|
3437
|
-
errorMessage = trimmed;
|
|
3438
|
-
}
|
|
3609
|
+
if (status !== "PROCESSING" && status !== "COMPLETED") {
|
|
3439
3610
|
throw new CofheError({
|
|
3440
3611
|
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3441
|
-
message:
|
|
3442
|
-
hint: "Check the threshold network URL and request parameters.",
|
|
3612
|
+
message: "decrypt status response has invalid status",
|
|
3443
3613
|
context: {
|
|
3444
|
-
|
|
3445
|
-
status
|
|
3446
|
-
statusText: response.statusText,
|
|
3447
|
-
body,
|
|
3448
|
-
responseText
|
|
3614
|
+
value,
|
|
3615
|
+
status
|
|
3449
3616
|
}
|
|
3450
3617
|
});
|
|
3451
3618
|
}
|
|
3452
|
-
|
|
3453
|
-
try {
|
|
3454
|
-
rawJson = JSON.parse(responseText);
|
|
3455
|
-
} catch (e) {
|
|
3619
|
+
if (typeof submittedAt !== "string" || submittedAt.trim().length === 0) {
|
|
3456
3620
|
throw new CofheError({
|
|
3457
3621
|
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3458
|
-
message:
|
|
3459
|
-
cause: e instanceof Error ? e : void 0,
|
|
3622
|
+
message: "decrypt status response missing submitted_at",
|
|
3460
3623
|
context: {
|
|
3461
|
-
|
|
3462
|
-
body,
|
|
3463
|
-
responseText
|
|
3624
|
+
value
|
|
3464
3625
|
}
|
|
3465
3626
|
});
|
|
3466
3627
|
}
|
|
3467
|
-
|
|
3468
|
-
|
|
3628
|
+
return value;
|
|
3629
|
+
}
|
|
3630
|
+
async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, permission, overallStartTime, onPoll) {
|
|
3631
|
+
const body = {
|
|
3632
|
+
ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
|
|
3633
|
+
host_chain_id: chainId
|
|
3634
|
+
};
|
|
3635
|
+
if (permission) {
|
|
3636
|
+
body.permit = permission;
|
|
3637
|
+
}
|
|
3638
|
+
let attemptIndex = 0;
|
|
3639
|
+
for (; ; ) {
|
|
3640
|
+
let response;
|
|
3641
|
+
try {
|
|
3642
|
+
response = await fetch(`${thresholdNetworkUrl}/v2/decrypt`, {
|
|
3643
|
+
method: "POST",
|
|
3644
|
+
headers: {
|
|
3645
|
+
"Content-Type": "application/json"
|
|
3646
|
+
},
|
|
3647
|
+
body: JSON.stringify(body)
|
|
3648
|
+
});
|
|
3649
|
+
} catch (e) {
|
|
3650
|
+
throw new CofheError({
|
|
3651
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3652
|
+
message: `decrypt request failed`,
|
|
3653
|
+
hint: "Ensure the threshold network URL is valid and reachable.",
|
|
3654
|
+
cause: e instanceof Error ? e : void 0,
|
|
3655
|
+
context: {
|
|
3656
|
+
thresholdNetworkUrl,
|
|
3657
|
+
body,
|
|
3658
|
+
attemptIndex
|
|
3659
|
+
}
|
|
3660
|
+
});
|
|
3661
|
+
}
|
|
3662
|
+
if (!response.ok) {
|
|
3663
|
+
let errorMessage = `HTTP ${response.status}`;
|
|
3664
|
+
try {
|
|
3665
|
+
const errorBody = await response.json();
|
|
3666
|
+
const maybeMessage = errorBody.error_message || errorBody.message;
|
|
3667
|
+
if (typeof maybeMessage === "string" && maybeMessage.length > 0)
|
|
3668
|
+
errorMessage = maybeMessage;
|
|
3669
|
+
} catch {
|
|
3670
|
+
errorMessage = response.statusText || errorMessage;
|
|
3671
|
+
}
|
|
3672
|
+
throw new CofheError({
|
|
3673
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3674
|
+
message: `decrypt request failed: ${errorMessage}`,
|
|
3675
|
+
hint: "Check the threshold network URL and request parameters.",
|
|
3676
|
+
context: {
|
|
3677
|
+
thresholdNetworkUrl,
|
|
3678
|
+
status: response.status,
|
|
3679
|
+
statusText: response.statusText,
|
|
3680
|
+
body,
|
|
3681
|
+
attemptIndex
|
|
3682
|
+
}
|
|
3683
|
+
});
|
|
3684
|
+
}
|
|
3685
|
+
let submitResponse;
|
|
3686
|
+
if (response.status !== 204) {
|
|
3687
|
+
let rawJson;
|
|
3688
|
+
try {
|
|
3689
|
+
rawJson = await response.json();
|
|
3690
|
+
} catch (e) {
|
|
3691
|
+
throw new CofheError({
|
|
3692
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3693
|
+
message: `Failed to parse decrypt submit response`,
|
|
3694
|
+
cause: e instanceof Error ? e : void 0,
|
|
3695
|
+
context: {
|
|
3696
|
+
thresholdNetworkUrl,
|
|
3697
|
+
body,
|
|
3698
|
+
attemptIndex
|
|
3699
|
+
}
|
|
3700
|
+
});
|
|
3701
|
+
}
|
|
3702
|
+
submitResponse = assertDecryptSubmitResponseV2(rawJson);
|
|
3703
|
+
if (Array.isArray(submitResponse.decrypted) && typeof submitResponse.signature === "string") {
|
|
3704
|
+
return {
|
|
3705
|
+
kind: "completed",
|
|
3706
|
+
...parseCompletedDecryptResponseV2({
|
|
3707
|
+
value: submitResponse,
|
|
3708
|
+
thresholdNetworkUrl,
|
|
3709
|
+
requestId: submitResponse.request_id
|
|
3710
|
+
})
|
|
3711
|
+
};
|
|
3712
|
+
}
|
|
3713
|
+
if (submitResponse.request_id) {
|
|
3714
|
+
return { kind: "request_id", requestId: submitResponse.request_id };
|
|
3715
|
+
}
|
|
3716
|
+
}
|
|
3717
|
+
if (response.status === 204) {
|
|
3718
|
+
const elapsedMs = Date.now() - overallStartTime;
|
|
3719
|
+
if (elapsedMs > DECRYPT_TIMEOUT_MS) {
|
|
3720
|
+
throw new CofheError({
|
|
3721
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3722
|
+
message: `decrypt submit retried without receiving request_id for ${DECRYPT_TIMEOUT_MS}ms`,
|
|
3723
|
+
hint: "The ciphertext may still be propagating. Try again later.",
|
|
3724
|
+
context: {
|
|
3725
|
+
thresholdNetworkUrl,
|
|
3726
|
+
body,
|
|
3727
|
+
attemptIndex,
|
|
3728
|
+
timeoutMs: DECRYPT_TIMEOUT_MS,
|
|
3729
|
+
submitResponse,
|
|
3730
|
+
status: response.status
|
|
3731
|
+
}
|
|
3732
|
+
});
|
|
3733
|
+
}
|
|
3734
|
+
onPoll?.({
|
|
3735
|
+
operation: "decrypt",
|
|
3736
|
+
requestId: "",
|
|
3737
|
+
attemptIndex,
|
|
3738
|
+
elapsedMs,
|
|
3739
|
+
intervalMs: SUBMIT_RETRY_INTERVAL_MS2,
|
|
3740
|
+
timeoutMs: DECRYPT_TIMEOUT_MS
|
|
3741
|
+
});
|
|
3742
|
+
await new Promise((resolve) => setTimeout(resolve, SUBMIT_RETRY_INTERVAL_MS2));
|
|
3743
|
+
attemptIndex += 1;
|
|
3744
|
+
continue;
|
|
3745
|
+
}
|
|
3469
3746
|
throw new CofheError({
|
|
3470
3747
|
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3471
|
-
message: `decrypt
|
|
3748
|
+
message: `decrypt submit response missing request_id`,
|
|
3472
3749
|
context: {
|
|
3473
3750
|
thresholdNetworkUrl,
|
|
3474
3751
|
body,
|
|
3475
|
-
|
|
3752
|
+
submitResponse,
|
|
3753
|
+
attemptIndex
|
|
3476
3754
|
}
|
|
3477
3755
|
});
|
|
3478
3756
|
}
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3757
|
+
}
|
|
3758
|
+
async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartTime, onPoll) {
|
|
3759
|
+
let attemptIndex = 0;
|
|
3760
|
+
while (true) {
|
|
3761
|
+
const elapsedMs = Date.now() - overallStartTime;
|
|
3762
|
+
const intervalMs = computeMinuteRampPollIntervalMs(elapsedMs, {
|
|
3763
|
+
minIntervalMs: POLL_INTERVAL_MS2,
|
|
3764
|
+
maxIntervalMs: POLL_MAX_INTERVAL_MS2
|
|
3765
|
+
});
|
|
3766
|
+
onPoll?.({
|
|
3767
|
+
operation: "decrypt",
|
|
3768
|
+
requestId,
|
|
3769
|
+
attemptIndex,
|
|
3770
|
+
elapsedMs,
|
|
3771
|
+
intervalMs,
|
|
3772
|
+
timeoutMs: DECRYPT_TIMEOUT_MS
|
|
3773
|
+
});
|
|
3774
|
+
if (elapsedMs > DECRYPT_TIMEOUT_MS) {
|
|
3775
|
+
throw new CofheError({
|
|
3776
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3777
|
+
message: `decrypt polling timed out after ${DECRYPT_TIMEOUT_MS}ms`,
|
|
3778
|
+
hint: "The request may still be processing. Try again later.",
|
|
3779
|
+
context: {
|
|
3780
|
+
thresholdNetworkUrl,
|
|
3781
|
+
requestId,
|
|
3782
|
+
timeoutMs: DECRYPT_TIMEOUT_MS
|
|
3783
|
+
}
|
|
3784
|
+
});
|
|
3785
|
+
}
|
|
3786
|
+
let response;
|
|
3787
|
+
try {
|
|
3788
|
+
response = await fetch(`${thresholdNetworkUrl}/v2/decrypt/${requestId}`, {
|
|
3789
|
+
method: "GET",
|
|
3790
|
+
headers: {
|
|
3791
|
+
"Content-Type": "application/json"
|
|
3792
|
+
}
|
|
3793
|
+
});
|
|
3794
|
+
} catch (e) {
|
|
3795
|
+
throw new CofheError({
|
|
3796
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3797
|
+
message: `decrypt status poll failed`,
|
|
3798
|
+
hint: "Ensure the threshold network URL is valid and reachable.",
|
|
3799
|
+
cause: e instanceof Error ? e : void 0,
|
|
3800
|
+
context: {
|
|
3801
|
+
thresholdNetworkUrl,
|
|
3802
|
+
requestId
|
|
3803
|
+
}
|
|
3804
|
+
});
|
|
3805
|
+
}
|
|
3806
|
+
if (response.status === 404) {
|
|
3807
|
+
throw new CofheError({
|
|
3808
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3809
|
+
message: `decrypt request not found: ${requestId}`,
|
|
3810
|
+
hint: "The request may have expired or been invalid.",
|
|
3811
|
+
context: {
|
|
3812
|
+
thresholdNetworkUrl,
|
|
3813
|
+
requestId
|
|
3814
|
+
}
|
|
3815
|
+
});
|
|
3816
|
+
}
|
|
3817
|
+
if (!response.ok) {
|
|
3818
|
+
let errorMessage = `HTTP ${response.status}`;
|
|
3819
|
+
try {
|
|
3820
|
+
const errorBody = await response.json();
|
|
3821
|
+
const maybeMessage = errorBody.error_message || errorBody.message;
|
|
3822
|
+
if (typeof maybeMessage === "string" && maybeMessage.length > 0)
|
|
3823
|
+
errorMessage = maybeMessage;
|
|
3824
|
+
} catch {
|
|
3825
|
+
errorMessage = response.statusText || errorMessage;
|
|
3826
|
+
}
|
|
3827
|
+
throw new CofheError({
|
|
3828
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3829
|
+
message: `decrypt status poll failed: ${errorMessage}`,
|
|
3830
|
+
context: {
|
|
3831
|
+
thresholdNetworkUrl,
|
|
3832
|
+
requestId,
|
|
3833
|
+
status: response.status,
|
|
3834
|
+
statusText: response.statusText
|
|
3835
|
+
}
|
|
3836
|
+
});
|
|
3837
|
+
}
|
|
3838
|
+
let rawJson;
|
|
3839
|
+
try {
|
|
3840
|
+
rawJson = await response.json();
|
|
3841
|
+
} catch (e) {
|
|
3842
|
+
throw new CofheError({
|
|
3843
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3844
|
+
message: `Failed to parse decrypt status response`,
|
|
3845
|
+
cause: e instanceof Error ? e : void 0,
|
|
3846
|
+
context: {
|
|
3847
|
+
thresholdNetworkUrl,
|
|
3848
|
+
requestId
|
|
3849
|
+
}
|
|
3850
|
+
});
|
|
3851
|
+
}
|
|
3852
|
+
const statusResponse = assertDecryptStatusResponseV2(rawJson);
|
|
3853
|
+
if (statusResponse.status === "COMPLETED") {
|
|
3854
|
+
return parseCompletedDecryptResponseV2({
|
|
3855
|
+
value: statusResponse,
|
|
3856
|
+
thresholdNetworkUrl,
|
|
3857
|
+
requestId
|
|
3858
|
+
});
|
|
3859
|
+
}
|
|
3860
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
3861
|
+
attemptIndex += 1;
|
|
3862
|
+
}
|
|
3863
|
+
throw new CofheError({
|
|
3864
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3865
|
+
message: "Polling loop exited unexpectedly",
|
|
3866
|
+
context: {
|
|
3867
|
+
thresholdNetworkUrl,
|
|
3868
|
+
requestId
|
|
3869
|
+
}
|
|
3870
|
+
});
|
|
3871
|
+
}
|
|
3872
|
+
async function tnDecryptV2(params) {
|
|
3873
|
+
const { thresholdNetworkUrl, ctHash, chainId, permission, onPoll } = params;
|
|
3874
|
+
const overallStartTime = Date.now();
|
|
3875
|
+
const submitResult = await submitDecryptRequestV2(
|
|
3876
|
+
thresholdNetworkUrl,
|
|
3877
|
+
ctHash,
|
|
3878
|
+
chainId,
|
|
3879
|
+
permission,
|
|
3880
|
+
overallStartTime,
|
|
3881
|
+
onPoll
|
|
3882
|
+
);
|
|
3883
|
+
if (submitResult.kind === "completed") {
|
|
3884
|
+
return submitResult;
|
|
3885
|
+
}
|
|
3886
|
+
return await pollDecryptStatusV2(thresholdNetworkUrl, submitResult.requestId, overallStartTime, onPoll);
|
|
3482
3887
|
}
|
|
3483
3888
|
|
|
3484
3889
|
// core/decrypt/decryptForTxBuilder.ts
|
|
@@ -3487,6 +3892,7 @@ var DecryptForTxBuilder = class extends BaseBuilder {
|
|
|
3487
3892
|
permitHash;
|
|
3488
3893
|
permit;
|
|
3489
3894
|
permitSelection = "unset";
|
|
3895
|
+
pollCallback;
|
|
3490
3896
|
constructor(params) {
|
|
3491
3897
|
super({
|
|
3492
3898
|
config: params.config,
|
|
@@ -3512,6 +3918,10 @@ var DecryptForTxBuilder = class extends BaseBuilder {
|
|
|
3512
3918
|
getAccount() {
|
|
3513
3919
|
return this.account;
|
|
3514
3920
|
}
|
|
3921
|
+
onPoll(callback) {
|
|
3922
|
+
this.pollCallback = callback;
|
|
3923
|
+
return this;
|
|
3924
|
+
}
|
|
3515
3925
|
withPermit(permitOrPermitHash) {
|
|
3516
3926
|
if (this.permitSelection === "with-permit") {
|
|
3517
3927
|
throw new CofheError({
|
|
@@ -3639,7 +4049,13 @@ var DecryptForTxBuilder = class extends BaseBuilder {
|
|
|
3639
4049
|
this.assertPublicClient();
|
|
3640
4050
|
const thresholdNetworkUrl = await this.getThresholdNetworkUrl();
|
|
3641
4051
|
const permission = permit ? PermitUtils.getPermission(permit, true) : null;
|
|
3642
|
-
const { decryptedValue, signature } = await
|
|
4052
|
+
const { decryptedValue, signature } = await tnDecryptV2({
|
|
4053
|
+
ctHash: this.ctHash,
|
|
4054
|
+
chainId: this.chainId,
|
|
4055
|
+
permission,
|
|
4056
|
+
thresholdNetworkUrl,
|
|
4057
|
+
onPoll: this.pollCallback
|
|
4058
|
+
});
|
|
3643
4059
|
return {
|
|
3644
4060
|
ctHash: this.ctHash,
|
|
3645
4061
|
decryptedValue,
|
|
@@ -3657,7 +4073,6 @@ var DecryptForTxBuilder = class extends BaseBuilder {
|
|
|
3657
4073
|
const permit = await this.getResolvedPermit();
|
|
3658
4074
|
if (permit !== null) {
|
|
3659
4075
|
PermitUtils.validate(permit);
|
|
3660
|
-
PermitUtils.isValid(permit);
|
|
3661
4076
|
const chainId = permit._signedDomain.chainId;
|
|
3662
4077
|
if (chainId === hardhat2.id) {
|
|
3663
4078
|
return await this.mocksDecryptForTx(permit);
|
|
@@ -3678,6 +4093,35 @@ var DecryptForTxBuilder = class extends BaseBuilder {
|
|
|
3678
4093
|
}
|
|
3679
4094
|
}
|
|
3680
4095
|
};
|
|
4096
|
+
var decryptResultSignerAbi = viem.parseAbi(["function decryptResultSigner() view returns (address)"]);
|
|
4097
|
+
var UINT_TYPE_MASK2 = 0x7fn;
|
|
4098
|
+
var TYPE_BYTE_OFFSET2 = 8n;
|
|
4099
|
+
var getEncryptionTypeFromCtHash2 = (ctHash) => Number(ctHash >> TYPE_BYTE_OFFSET2 & UINT_TYPE_MASK2);
|
|
4100
|
+
var buildDecryptResultHash = (ctHash, cleartext, chainId) => {
|
|
4101
|
+
const encryptionType = getEncryptionTypeFromCtHash2(ctHash);
|
|
4102
|
+
return viem.keccak256(
|
|
4103
|
+
viem.encodePacked(["uint256", "uint32", "uint64", "uint256"], [cleartext, encryptionType, BigInt(chainId), ctHash])
|
|
4104
|
+
);
|
|
4105
|
+
};
|
|
4106
|
+
async function verifyDecryptResult(handle, cleartext, signature, publicClient) {
|
|
4107
|
+
const chainId = publicClient.chain?.id ?? await publicClient.getChainId();
|
|
4108
|
+
const expectedSigner = await publicClient.readContract({
|
|
4109
|
+
address: TASK_MANAGER_ADDRESS,
|
|
4110
|
+
abi: decryptResultSignerAbi,
|
|
4111
|
+
functionName: "decryptResultSigner",
|
|
4112
|
+
args: []
|
|
4113
|
+
});
|
|
4114
|
+
if (viem.isAddressEqual(expectedSigner, viem.zeroAddress))
|
|
4115
|
+
return true;
|
|
4116
|
+
const ctHash = BigInt(handle);
|
|
4117
|
+
const messageHash = buildDecryptResultHash(ctHash, cleartext, chainId);
|
|
4118
|
+
try {
|
|
4119
|
+
const recovered = await viem.recoverAddress({ hash: messageHash, signature });
|
|
4120
|
+
return viem.isAddressEqual(recovered, expectedSigner);
|
|
4121
|
+
} catch {
|
|
4122
|
+
return false;
|
|
4123
|
+
}
|
|
4124
|
+
}
|
|
3681
4125
|
|
|
3682
4126
|
// core/client.ts
|
|
3683
4127
|
var InitialConnectStore = {
|
|
@@ -3796,6 +4240,11 @@ function createCofheClientBase(opts) {
|
|
|
3796
4240
|
requireConnected: _requireConnected
|
|
3797
4241
|
});
|
|
3798
4242
|
}
|
|
4243
|
+
function verifyDecryptResult2(handle, cleartext, signature) {
|
|
4244
|
+
_requireConnected();
|
|
4245
|
+
const { publicClient } = connectStore.getState();
|
|
4246
|
+
return verifyDecryptResult(handle, cleartext, signature, publicClient);
|
|
4247
|
+
}
|
|
3799
4248
|
const _getChainIdAndAccount = (chainId, account) => {
|
|
3800
4249
|
const state = connectStore.getState();
|
|
3801
4250
|
const _chainId = chainId ?? state.chainId;
|
|
@@ -3847,19 +4296,19 @@ function createCofheClientBase(opts) {
|
|
|
3847
4296
|
return permits.getOrCreateSharingPermit(publicClient, walletClient, options, _chainId, _account);
|
|
3848
4297
|
},
|
|
3849
4298
|
// Retrieval methods (auto-fill chainId/account)
|
|
3850
|
-
getPermit:
|
|
4299
|
+
getPermit: (hash, chainId, account) => {
|
|
3851
4300
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
3852
4301
|
return permits.getPermit(_chainId, _account, hash);
|
|
3853
4302
|
},
|
|
3854
|
-
getPermits:
|
|
4303
|
+
getPermits: (chainId, account) => {
|
|
3855
4304
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
3856
4305
|
return permits.getPermits(_chainId, _account);
|
|
3857
4306
|
},
|
|
3858
|
-
getActivePermit:
|
|
4307
|
+
getActivePermit: (chainId, account) => {
|
|
3859
4308
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
3860
4309
|
return permits.getActivePermit(_chainId, _account);
|
|
3861
4310
|
},
|
|
3862
|
-
getActivePermitHash:
|
|
4311
|
+
getActivePermitHash: (chainId, account) => {
|
|
3863
4312
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
3864
4313
|
return permits.getActivePermitHash(_chainId, _account);
|
|
3865
4314
|
},
|
|
@@ -3878,6 +4327,7 @@ function createCofheClientBase(opts) {
|
|
|
3878
4327
|
},
|
|
3879
4328
|
// Utils (no context needed)
|
|
3880
4329
|
getHash: permits.getHash,
|
|
4330
|
+
export: permits.export,
|
|
3881
4331
|
serialize: permits.serialize,
|
|
3882
4332
|
deserialize: permits.deserialize
|
|
3883
4333
|
};
|
|
@@ -3906,6 +4356,7 @@ function createCofheClientBase(opts) {
|
|
|
3906
4356
|
*/
|
|
3907
4357
|
decryptHandle: decryptForView,
|
|
3908
4358
|
decryptForTx,
|
|
4359
|
+
verifyDecryptResult: verifyDecryptResult2,
|
|
3909
4360
|
permits: clientPermits
|
|
3910
4361
|
// Add SDK-specific methods below that require connection
|
|
3911
4362
|
// Example:
|
|
@@ -3915,12 +4366,19 @@ function createCofheClientBase(opts) {
|
|
|
3915
4366
|
// },
|
|
3916
4367
|
};
|
|
3917
4368
|
}
|
|
3918
|
-
|
|
4369
|
+
|
|
4370
|
+
// web/const.ts
|
|
4371
|
+
var hasDOM = typeof globalThis?.document !== "undefined" && typeof globalThis?.window !== "undefined";
|
|
4372
|
+
|
|
4373
|
+
// web/storage.ts
|
|
4374
|
+
var createWebStorage = (opts = { enableLog: false }) => {
|
|
4375
|
+
if (!hasDOM)
|
|
4376
|
+
throw new Error("createWebStorage can only be used in a browser environment");
|
|
3919
4377
|
const client = iframeSharedStorage.constructClient({
|
|
3920
4378
|
iframe: {
|
|
3921
4379
|
src: "https://iframe-shared-storage.vercel.app/hub.html",
|
|
3922
4380
|
messagingOptions: {
|
|
3923
|
-
enableLog: "both"
|
|
4381
|
+
enableLog: opts.enableLog ? "both" : void 0
|
|
3924
4382
|
},
|
|
3925
4383
|
iframeReadyTimeoutMs: 3e4,
|
|
3926
4384
|
// if the iframe is not initied during this interval AND a reuqest is made, such request will throw an error
|
|
@@ -3943,6 +4401,16 @@ var createWebStorage = () => {
|
|
|
3943
4401
|
}
|
|
3944
4402
|
};
|
|
3945
4403
|
};
|
|
4404
|
+
function createSsrStorage() {
|
|
4405
|
+
console.warn("using no-op server-side SSR storage");
|
|
4406
|
+
return {
|
|
4407
|
+
getItem: async () => null,
|
|
4408
|
+
setItem: async () => {
|
|
4409
|
+
},
|
|
4410
|
+
removeItem: async () => {
|
|
4411
|
+
}
|
|
4412
|
+
};
|
|
4413
|
+
}
|
|
3946
4414
|
|
|
3947
4415
|
// web/workerManager.ts
|
|
3948
4416
|
var ZkProveWorkerManager = class {
|
|
@@ -3968,7 +4436,7 @@ var ZkProveWorkerManager = class {
|
|
|
3968
4436
|
return;
|
|
3969
4437
|
}
|
|
3970
4438
|
try {
|
|
3971
|
-
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" });
|
|
4439
|
+
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" });
|
|
3972
4440
|
} catch (error) {
|
|
3973
4441
|
reject(new Error(`Failed to create worker: ${error}`));
|
|
3974
4442
|
return;
|
|
@@ -4098,16 +4566,22 @@ var fromHexString2 = (hexString) => {
|
|
|
4098
4566
|
return new Uint8Array();
|
|
4099
4567
|
return new Uint8Array(arr.map((byte) => parseInt(byte, 16)));
|
|
4100
4568
|
};
|
|
4569
|
+
var _deserializeTfhePublicKey = (buff) => {
|
|
4570
|
+
return init.TfheCompactPublicKey.safe_deserialize(fromHexString2(buff), TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
|
|
4571
|
+
};
|
|
4572
|
+
var _deserializeCompactPkeCrs = (buff) => {
|
|
4573
|
+
return init.CompactPkeCrs.safe_deserialize(fromHexString2(buff), TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
|
|
4574
|
+
};
|
|
4101
4575
|
var tfhePublicKeyDeserializer = (buff) => {
|
|
4102
|
-
|
|
4576
|
+
_deserializeTfhePublicKey(buff);
|
|
4103
4577
|
};
|
|
4104
4578
|
var compactPkeCrsDeserializer = (buff) => {
|
|
4105
|
-
|
|
4579
|
+
_deserializeCompactPkeCrs(buff);
|
|
4106
4580
|
};
|
|
4107
4581
|
var zkBuilderAndCrsGenerator = (fhe, crs) => {
|
|
4108
|
-
const fhePublicKey =
|
|
4582
|
+
const fhePublicKey = _deserializeTfhePublicKey(fhe);
|
|
4109
4583
|
const zkBuilder = init.ProvenCompactCiphertextList.builder(fhePublicKey);
|
|
4110
|
-
const zkCrs =
|
|
4584
|
+
const zkCrs = _deserializeCompactPkeCrs(crs);
|
|
4111
4585
|
return { zkBuilder, zkCrs };
|
|
4112
4586
|
};
|
|
4113
4587
|
async function zkProveWithWorker2(fheKeyHex, crsHex, items, metadata) {
|
|
@@ -4122,7 +4596,7 @@ function createCofheConfig(config) {
|
|
|
4122
4596
|
return createCofheConfigBase({
|
|
4123
4597
|
environment: "web",
|
|
4124
4598
|
...config,
|
|
4125
|
-
fheKeyStorage: config.fheKeyStorage === null ? null : config.fheKeyStorage ?? createWebStorage()
|
|
4599
|
+
fheKeyStorage: config.fheKeyStorage === null ? null : config.fheKeyStorage ?? (hasDOM ? createWebStorage() : createSsrStorage())
|
|
4126
4600
|
});
|
|
4127
4601
|
}
|
|
4128
4602
|
function createCofheClient(config) {
|
|
@@ -4152,4 +4626,6 @@ exports.areWorkersAvailable = areWorkersAvailable;
|
|
|
4152
4626
|
exports.createCofheClient = createCofheClient;
|
|
4153
4627
|
exports.createCofheClientWithCustomWorker = createCofheClientWithCustomWorker;
|
|
4154
4628
|
exports.createCofheConfig = createCofheConfig;
|
|
4629
|
+
exports.createSsrStorage = createSsrStorage;
|
|
4630
|
+
exports.hasDOM = hasDOM;
|
|
4155
4631
|
exports.terminateWorker = terminateWorker;
|