@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/node.cjs
CHANGED
|
@@ -12,25 +12,9 @@ var fs = require('fs');
|
|
|
12
12
|
var path = require('path');
|
|
13
13
|
var nodeTfhe = require('node-tfhe');
|
|
14
14
|
|
|
15
|
-
function
|
|
16
|
-
if (e && e.__esModule) return e;
|
|
17
|
-
var n = Object.create(null);
|
|
18
|
-
if (e) {
|
|
19
|
-
Object.keys(e).forEach(function (k) {
|
|
20
|
-
if (k !== 'default') {
|
|
21
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
22
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
23
|
-
enumerable: true,
|
|
24
|
-
get: function () { return e[k]; }
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
n.default = e;
|
|
30
|
-
return Object.freeze(n);
|
|
31
|
-
}
|
|
15
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
32
16
|
|
|
33
|
-
var
|
|
17
|
+
var nacl__default = /*#__PURE__*/_interopDefault(nacl);
|
|
34
18
|
|
|
35
19
|
// core/client.ts
|
|
36
20
|
|
|
@@ -123,6 +107,16 @@ var bigintSafeJsonStringify = (value) => {
|
|
|
123
107
|
};
|
|
124
108
|
var isCofheError = (error) => error instanceof CofheError;
|
|
125
109
|
|
|
110
|
+
// core/consts.ts
|
|
111
|
+
var TASK_MANAGER_ADDRESS = "0xeA30c4B8b44078Bbf8a6ef5b9f1eC1626C7848D9";
|
|
112
|
+
var MOCKS_ZK_VERIFIER_ADDRESS = "0x0000000000000000000000000000000000005001";
|
|
113
|
+
var MOCKS_THRESHOLD_NETWORK_ADDRESS = "0x0000000000000000000000000000000000005002";
|
|
114
|
+
var MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY = "0x6C8D7F768A6BB4AAFE85E8A2F5A9680355239C7E14646ED62B044E39DE154512";
|
|
115
|
+
var MOCKS_DECRYPT_RESULT_SIGNER_PRIVATE_KEY = "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d";
|
|
116
|
+
var TFHE_RS_ZK_MAX_BITS = 2048;
|
|
117
|
+
var TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT = BigInt(1 << 30);
|
|
118
|
+
var TFHE_RS_KEY_VERSION = 2;
|
|
119
|
+
|
|
126
120
|
// core/types.ts
|
|
127
121
|
var FheUintUTypes = [
|
|
128
122
|
2 /* Uint8 */,
|
|
@@ -209,7 +203,6 @@ var MAX_UINT32 = 4294967295n;
|
|
|
209
203
|
var MAX_UINT64 = 18446744073709551615n;
|
|
210
204
|
var MAX_UINT128 = 340282366920938463463374607431768211455n;
|
|
211
205
|
var MAX_UINT160 = 1461501637330902918203684832716283019655932542975n;
|
|
212
|
-
var MAX_ENCRYPTABLE_BITS = 2048;
|
|
213
206
|
var zkPack = (items, builder) => {
|
|
214
207
|
let totalBits = 0;
|
|
215
208
|
for (const item of items) {
|
|
@@ -273,14 +266,14 @@ var zkPack = (items, builder) => {
|
|
|
273
266
|
}
|
|
274
267
|
}
|
|
275
268
|
}
|
|
276
|
-
if (totalBits >
|
|
269
|
+
if (totalBits > TFHE_RS_ZK_MAX_BITS) {
|
|
277
270
|
throw new CofheError({
|
|
278
271
|
code: "ZK_PACK_FAILED" /* ZkPackFailed */,
|
|
279
|
-
message: `Total bits ${totalBits} exceeds ${
|
|
280
|
-
hint: `Ensure that the total bits of the items to encrypt does not exceed ${
|
|
272
|
+
message: `Total bits ${totalBits} exceeds ${TFHE_RS_ZK_MAX_BITS}`,
|
|
273
|
+
hint: `Ensure that the total bits of the items to encrypt does not exceed ${TFHE_RS_ZK_MAX_BITS}`,
|
|
281
274
|
context: {
|
|
282
275
|
totalBits,
|
|
283
|
-
maxBits:
|
|
276
|
+
maxBits: TFHE_RS_ZK_MAX_BITS,
|
|
284
277
|
items
|
|
285
278
|
}
|
|
286
279
|
});
|
|
@@ -299,7 +292,7 @@ var zkProve = async (builder, crs, metadata) => {
|
|
|
299
292
|
1
|
|
300
293
|
// ZkComputeLoad.Verify
|
|
301
294
|
);
|
|
302
|
-
resolve(compactList.
|
|
295
|
+
resolve(compactList.safe_serialize(TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT));
|
|
303
296
|
}, 0);
|
|
304
297
|
});
|
|
305
298
|
};
|
|
@@ -475,15 +468,6 @@ var MockZkVerifierAbi = [
|
|
|
475
468
|
},
|
|
476
469
|
{ type: "error", name: "InvalidInputs", inputs: [] }
|
|
477
470
|
];
|
|
478
|
-
|
|
479
|
-
// core/consts.ts
|
|
480
|
-
var TASK_MANAGER_ADDRESS = "0xeA30c4B8b44078Bbf8a6ef5b9f1eC1626C7848D9";
|
|
481
|
-
var MOCKS_ZK_VERIFIER_ADDRESS = "0x0000000000000000000000000000000000005001";
|
|
482
|
-
var MOCKS_THRESHOLD_NETWORK_ADDRESS = "0x0000000000000000000000000000000000005002";
|
|
483
|
-
var MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY = "0x6C8D7F768A6BB4AAFE85E8A2F5A9680355239C7E14646ED62B044E39DE154512";
|
|
484
|
-
var MOCKS_DECRYPT_RESULT_SIGNER_PRIVATE_KEY = "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d";
|
|
485
|
-
|
|
486
|
-
// core/encrypt/cofheMocksZkVerifySign.ts
|
|
487
471
|
function createMockZkVerifierSigner() {
|
|
488
472
|
return viem.createWalletClient({
|
|
489
473
|
chain: chains.hardhat,
|
|
@@ -525,14 +509,14 @@ async function cofheMocksCheckEncryptableBits(items) {
|
|
|
525
509
|
}
|
|
526
510
|
}
|
|
527
511
|
}
|
|
528
|
-
if (totalBits >
|
|
512
|
+
if (totalBits > TFHE_RS_ZK_MAX_BITS) {
|
|
529
513
|
throw new CofheError({
|
|
530
514
|
code: "ZK_PACK_FAILED" /* ZkPackFailed */,
|
|
531
|
-
message: `Total bits ${totalBits} exceeds ${
|
|
532
|
-
hint: `Ensure that the total bits of the items to encrypt does not exceed ${
|
|
515
|
+
message: `Total bits ${totalBits} exceeds ${TFHE_RS_ZK_MAX_BITS}`,
|
|
516
|
+
hint: `Ensure that the total bits of the items to encrypt does not exceed ${TFHE_RS_ZK_MAX_BITS}`,
|
|
533
517
|
context: {
|
|
534
518
|
totalBits,
|
|
535
|
-
maxBits:
|
|
519
|
+
maxBits: TFHE_RS_ZK_MAX_BITS,
|
|
536
520
|
items
|
|
537
521
|
}
|
|
538
522
|
});
|
|
@@ -803,6 +787,7 @@ function getThresholdNetworkUrlOrThrow(config, chainId) {
|
|
|
803
787
|
}
|
|
804
788
|
return url;
|
|
805
789
|
}
|
|
790
|
+
var KEYSTORE_NAME = `cofhesdk-keys-v${TFHE_RS_KEY_VERSION}`;
|
|
806
791
|
function isValidPersistedState(state) {
|
|
807
792
|
if (state && typeof state === "object") {
|
|
808
793
|
if ("fhe" in state && "crs" in state) {
|
|
@@ -857,7 +842,7 @@ function createKeysStore(storage) {
|
|
|
857
842
|
};
|
|
858
843
|
const clearKeysStorage = async () => {
|
|
859
844
|
if (storage) {
|
|
860
|
-
await storage.removeItem(
|
|
845
|
+
await storage.removeItem(KEYSTORE_NAME);
|
|
861
846
|
}
|
|
862
847
|
};
|
|
863
848
|
const rehydrateKeysStore = async () => {
|
|
@@ -887,7 +872,7 @@ function createStoreWithPersit(storage) {
|
|
|
887
872
|
if (_error)
|
|
888
873
|
throw new Error(`onRehydrateStorage: Error rehydrating keys store: ${_error}`);
|
|
889
874
|
},
|
|
890
|
-
name:
|
|
875
|
+
name: KEYSTORE_NAME,
|
|
891
876
|
storage: middleware.createJSONStorage(() => storage),
|
|
892
877
|
merge: (persistedState, currentState) => {
|
|
893
878
|
const persisted = isValidPersistedState(persistedState) ? persistedState : DEFAULT_KEYS_STORE;
|
|
@@ -1612,7 +1597,7 @@ var SealingKey = class _SealingKey {
|
|
|
1612
1597
|
const ephemPublicKey = parsedData.public_key instanceof Uint8Array ? parsedData.public_key : new Uint8Array(parsedData.public_key);
|
|
1613
1598
|
const dataToDecrypt = parsedData.data instanceof Uint8Array ? parsedData.data : new Uint8Array(parsedData.data);
|
|
1614
1599
|
const privateKeyBytes = fromHexString(this.privateKey);
|
|
1615
|
-
const decryptedMessage =
|
|
1600
|
+
const decryptedMessage = nacl__default.default.box.open(dataToDecrypt, nonce, ephemPublicKey, privateKeyBytes);
|
|
1616
1601
|
if (!decryptedMessage) {
|
|
1617
1602
|
throw new Error("Failed to decrypt message");
|
|
1618
1603
|
}
|
|
@@ -1645,9 +1630,9 @@ var SealingKey = class _SealingKey {
|
|
|
1645
1630
|
static seal = (value, publicKey) => {
|
|
1646
1631
|
isString(publicKey);
|
|
1647
1632
|
isBigIntOrNumber(value);
|
|
1648
|
-
const ephemeralKeyPair =
|
|
1649
|
-
const nonce =
|
|
1650
|
-
const encryptedMessage =
|
|
1633
|
+
const ephemeralKeyPair = nacl__default.default.box.keyPair();
|
|
1634
|
+
const nonce = nacl__default.default.randomBytes(nacl__default.default.box.nonceLength);
|
|
1635
|
+
const encryptedMessage = nacl__default.default.box(toBeArray(value), nonce, fromHexString(publicKey), ephemeralKeyPair.secretKey);
|
|
1651
1636
|
return {
|
|
1652
1637
|
data: encryptedMessage,
|
|
1653
1638
|
public_key: ephemeralKeyPair.publicKey,
|
|
@@ -1656,7 +1641,7 @@ var SealingKey = class _SealingKey {
|
|
|
1656
1641
|
};
|
|
1657
1642
|
};
|
|
1658
1643
|
var GenerateSealingKey = () => {
|
|
1659
|
-
const sodiumKeypair =
|
|
1644
|
+
const sodiumKeypair = nacl__default.default.box.keyPair();
|
|
1660
1645
|
return new SealingKey(toHexString2(sodiumKeypair.secretKey), toHexString2(sodiumKeypair.publicKey));
|
|
1661
1646
|
};
|
|
1662
1647
|
var SerializedSealingPair = zod.z.object({
|
|
@@ -1814,9 +1799,9 @@ var ValidationUtils = {
|
|
|
1814
1799
|
return false;
|
|
1815
1800
|
},
|
|
1816
1801
|
/**
|
|
1817
|
-
*
|
|
1802
|
+
* Checks that a permit is signed and not expired.
|
|
1818
1803
|
*/
|
|
1819
|
-
|
|
1804
|
+
isSignedAndNotExpired: (permit) => {
|
|
1820
1805
|
if (ValidationUtils.isExpired(permit)) {
|
|
1821
1806
|
return { valid: false, error: "expired" };
|
|
1822
1807
|
}
|
|
@@ -1824,6 +1809,34 @@ var ValidationUtils = {
|
|
|
1824
1809
|
return { valid: false, error: "not-signed" };
|
|
1825
1810
|
}
|
|
1826
1811
|
return { valid: true, error: null };
|
|
1812
|
+
},
|
|
1813
|
+
/**
|
|
1814
|
+
* Asserts that a permit is signed and not expired.
|
|
1815
|
+
*
|
|
1816
|
+
* Throws `Error` with message:
|
|
1817
|
+
* - `Permit is expired`
|
|
1818
|
+
* - `Permit is not signed`
|
|
1819
|
+
*/
|
|
1820
|
+
assertSignedAndNotExpired: (permit) => {
|
|
1821
|
+
const result = ValidationUtils.isSignedAndNotExpired(permit);
|
|
1822
|
+
if (result.valid)
|
|
1823
|
+
return;
|
|
1824
|
+
if (result.error === "expired") {
|
|
1825
|
+
throw new Error("Permit is expired");
|
|
1826
|
+
}
|
|
1827
|
+
if (result.error === "not-signed") {
|
|
1828
|
+
throw new Error("Permit is not signed");
|
|
1829
|
+
}
|
|
1830
|
+
throw new Error("Permit is invalid");
|
|
1831
|
+
},
|
|
1832
|
+
isValid: (permit) => {
|
|
1833
|
+
const schema = permit.type === "self" ? SelfPermitValidator : permit.type === "sharing" ? SharingPermitValidator : permit.type === "recipient" ? ImportPermitValidator : null;
|
|
1834
|
+
if (schema == null)
|
|
1835
|
+
return { valid: false, error: "invalid-schema" };
|
|
1836
|
+
const schemaResult = schema.safeParse(permit);
|
|
1837
|
+
if (!schemaResult.success)
|
|
1838
|
+
return { valid: false, error: "invalid-schema" };
|
|
1839
|
+
return ValidationUtils.isSignedAndNotExpired(permit);
|
|
1827
1840
|
}
|
|
1828
1841
|
};
|
|
1829
1842
|
|
|
@@ -2205,9 +2218,9 @@ var PermitUtils = {
|
|
|
2205
2218
|
};
|
|
2206
2219
|
},
|
|
2207
2220
|
/**
|
|
2208
|
-
* Validate a permit
|
|
2221
|
+
* Validate a permit (schema-level validation)
|
|
2209
2222
|
*/
|
|
2210
|
-
|
|
2223
|
+
validateSchema: (permit) => {
|
|
2211
2224
|
if (permit.type === "self") {
|
|
2212
2225
|
return validateSelfPermit(permit);
|
|
2213
2226
|
} else if (permit.type === "sharing") {
|
|
@@ -2218,12 +2231,27 @@ var PermitUtils = {
|
|
|
2218
2231
|
throw new Error("Invalid permit type");
|
|
2219
2232
|
}
|
|
2220
2233
|
},
|
|
2234
|
+
/**
|
|
2235
|
+
* Validate a permit (holistic validation).
|
|
2236
|
+
*
|
|
2237
|
+
* This validates:
|
|
2238
|
+
* - Permit schema (shape + invariants)
|
|
2239
|
+
* - Permit is signed
|
|
2240
|
+
* - Permit is not expired
|
|
2241
|
+
*
|
|
2242
|
+
* For schema-only validation, use `validateSchema(permit)`.
|
|
2243
|
+
*/
|
|
2244
|
+
validate: (permit) => {
|
|
2245
|
+
const validated = PermitUtils.validateSchema(permit);
|
|
2246
|
+
ValidationUtils.assertSignedAndNotExpired(validated);
|
|
2247
|
+
return validated;
|
|
2248
|
+
},
|
|
2221
2249
|
/**
|
|
2222
2250
|
* Get the permission object from a permit (for use in contracts)
|
|
2223
2251
|
*/
|
|
2224
2252
|
getPermission: (permit, skipValidation = false) => {
|
|
2225
2253
|
if (!skipValidation) {
|
|
2226
|
-
PermitUtils.
|
|
2254
|
+
PermitUtils.validateSchema(permit);
|
|
2227
2255
|
}
|
|
2228
2256
|
return {
|
|
2229
2257
|
issuer: permit.issuer,
|
|
@@ -2289,8 +2317,17 @@ var PermitUtils = {
|
|
|
2289
2317
|
return ValidationUtils.isSigned(permit);
|
|
2290
2318
|
},
|
|
2291
2319
|
/**
|
|
2292
|
-
* Check if permit is
|
|
2320
|
+
* Check if permit is signed and not expired
|
|
2321
|
+
*/
|
|
2322
|
+
isSignedAndNotExpired: (permit) => {
|
|
2323
|
+
return ValidationUtils.isSignedAndNotExpired(permit);
|
|
2324
|
+
},
|
|
2325
|
+
/**
|
|
2326
|
+
* Assert that permit is signed and not expired
|
|
2293
2327
|
*/
|
|
2328
|
+
assertSignedAndNotExpired: (permit) => {
|
|
2329
|
+
return ValidationUtils.assertSignedAndNotExpired(permit);
|
|
2330
|
+
},
|
|
2294
2331
|
isValid: (permit) => {
|
|
2295
2332
|
return ValidationUtils.isValid(permit);
|
|
2296
2333
|
},
|
|
@@ -2468,19 +2505,22 @@ var importShared = async (options, publicClient, walletClient) => {
|
|
|
2468
2505
|
var getHash = (permit) => {
|
|
2469
2506
|
return PermitUtils.getHash(permit);
|
|
2470
2507
|
};
|
|
2508
|
+
var exportShared = (permit) => {
|
|
2509
|
+
return PermitUtils.export(permit);
|
|
2510
|
+
};
|
|
2471
2511
|
var serialize = (permit) => {
|
|
2472
2512
|
return PermitUtils.serialize(permit);
|
|
2473
2513
|
};
|
|
2474
2514
|
var deserialize = (serialized) => {
|
|
2475
2515
|
return PermitUtils.deserialize(serialized);
|
|
2476
2516
|
};
|
|
2477
|
-
var getPermit2 =
|
|
2517
|
+
var getPermit2 = (chainId, account, hash) => {
|
|
2478
2518
|
return permitStore.getPermit(chainId, account, hash);
|
|
2479
2519
|
};
|
|
2480
|
-
var getPermits2 =
|
|
2520
|
+
var getPermits2 = (chainId, account) => {
|
|
2481
2521
|
return permitStore.getPermits(chainId, account);
|
|
2482
2522
|
};
|
|
2483
|
-
var getActivePermit2 =
|
|
2523
|
+
var getActivePermit2 = (chainId, account) => {
|
|
2484
2524
|
return permitStore.getActivePermit(chainId, account);
|
|
2485
2525
|
};
|
|
2486
2526
|
var getActivePermitHash2 = (chainId, account) => {
|
|
@@ -2518,6 +2558,7 @@ var permits = {
|
|
|
2518
2558
|
getOrCreateSelfPermit,
|
|
2519
2559
|
getOrCreateSharingPermit,
|
|
2520
2560
|
getHash,
|
|
2561
|
+
export: exportShared,
|
|
2521
2562
|
serialize,
|
|
2522
2563
|
deserialize,
|
|
2523
2564
|
getPermit: getPermit2,
|
|
@@ -2760,9 +2801,19 @@ async function cofheMocksDecryptForView(ctHash, utype, permit, publicClient) {
|
|
|
2760
2801
|
return unsealed;
|
|
2761
2802
|
}
|
|
2762
2803
|
|
|
2804
|
+
// core/decrypt/polling.ts
|
|
2805
|
+
function computeMinuteRampPollIntervalMs(elapsedMs, params) {
|
|
2806
|
+
const elapsedSeconds = Math.floor(elapsedMs / 1e3);
|
|
2807
|
+
const intervalSeconds = 1 + Math.floor(elapsedSeconds / 60);
|
|
2808
|
+
const intervalMs = intervalSeconds * 1e3;
|
|
2809
|
+
return Math.min(params.maxIntervalMs, Math.max(params.minIntervalMs, intervalMs));
|
|
2810
|
+
}
|
|
2811
|
+
|
|
2763
2812
|
// core/decrypt/tnSealOutputV2.ts
|
|
2764
2813
|
var POLL_INTERVAL_MS = 1e3;
|
|
2765
|
-
var
|
|
2814
|
+
var POLL_MAX_INTERVAL_MS = 1e4;
|
|
2815
|
+
var SEAL_OUTPUT_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
2816
|
+
var SUBMIT_RETRY_INTERVAL_MS = 1e3;
|
|
2766
2817
|
function numberArrayToUint8Array(arr) {
|
|
2767
2818
|
return new Uint8Array(arr);
|
|
2768
2819
|
}
|
|
@@ -2779,93 +2830,193 @@ function convertSealedData(sealed) {
|
|
|
2779
2830
|
nonce: numberArrayToUint8Array(sealed.nonce)
|
|
2780
2831
|
};
|
|
2781
2832
|
}
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
method: "POST",
|
|
2792
|
-
headers: {
|
|
2793
|
-
"Content-Type": "application/json"
|
|
2794
|
-
},
|
|
2795
|
-
body: JSON.stringify(body)
|
|
2796
|
-
});
|
|
2797
|
-
} catch (e) {
|
|
2798
|
-
throw new CofheError({
|
|
2799
|
-
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
2800
|
-
message: `sealOutput request failed`,
|
|
2801
|
-
hint: "Ensure the threshold network URL is valid and reachable.",
|
|
2802
|
-
cause: e instanceof Error ? e : void 0,
|
|
2803
|
-
context: {
|
|
2804
|
-
thresholdNetworkUrl,
|
|
2805
|
-
body
|
|
2806
|
-
}
|
|
2807
|
-
});
|
|
2833
|
+
function getSealedDataFromSubmitResponse(value) {
|
|
2834
|
+
if (value.sealed)
|
|
2835
|
+
return value.sealed;
|
|
2836
|
+
if (Array.isArray(value.sealed_data) && Array.isArray(value.ephemeral_public_key) && Array.isArray(value.nonce)) {
|
|
2837
|
+
return {
|
|
2838
|
+
data: value.sealed_data,
|
|
2839
|
+
public_key: value.ephemeral_public_key,
|
|
2840
|
+
nonce: value.nonce
|
|
2841
|
+
};
|
|
2808
2842
|
}
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
errorMessage = response.statusText || errorMessage;
|
|
2816
|
-
}
|
|
2843
|
+
return void 0;
|
|
2844
|
+
}
|
|
2845
|
+
function parseCompletedSealOutputResponse(params) {
|
|
2846
|
+
const { value, thresholdNetworkUrl, requestId } = params;
|
|
2847
|
+
if (value.is_succeed === false) {
|
|
2848
|
+
const errorMessage = value.error_message || "Unknown error";
|
|
2817
2849
|
throw new CofheError({
|
|
2818
2850
|
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
2819
2851
|
message: `sealOutput request failed: ${errorMessage}`,
|
|
2820
|
-
hint: "Check the threshold network URL and request parameters.",
|
|
2821
2852
|
context: {
|
|
2822
2853
|
thresholdNetworkUrl,
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
body
|
|
2854
|
+
requestId,
|
|
2855
|
+
response: value
|
|
2826
2856
|
}
|
|
2827
2857
|
});
|
|
2828
2858
|
}
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
submitResponse = await response.json();
|
|
2832
|
-
} catch (e) {
|
|
2859
|
+
const sealed = "sealed" in value ? value.sealed : getSealedDataFromSubmitResponse(value);
|
|
2860
|
+
if (!sealed) {
|
|
2833
2861
|
throw new CofheError({
|
|
2834
|
-
code: "
|
|
2835
|
-
message: `
|
|
2836
|
-
cause: e instanceof Error ? e : void 0,
|
|
2862
|
+
code: "SEAL_OUTPUT_RETURNED_NULL" /* SealOutputReturnedNull */,
|
|
2863
|
+
message: `sealOutput request completed but returned no sealed data`,
|
|
2837
2864
|
context: {
|
|
2838
2865
|
thresholdNetworkUrl,
|
|
2839
|
-
|
|
2866
|
+
requestId,
|
|
2867
|
+
response: value
|
|
2840
2868
|
}
|
|
2841
2869
|
});
|
|
2842
2870
|
}
|
|
2843
|
-
|
|
2871
|
+
return convertSealedData(sealed);
|
|
2872
|
+
}
|
|
2873
|
+
async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, permission, overallStartTime, onPoll) {
|
|
2874
|
+
const body = {
|
|
2875
|
+
ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
|
|
2876
|
+
host_chain_id: chainId,
|
|
2877
|
+
permit: permission
|
|
2878
|
+
};
|
|
2879
|
+
let attemptIndex = 0;
|
|
2880
|
+
for (; ; ) {
|
|
2881
|
+
let response;
|
|
2882
|
+
try {
|
|
2883
|
+
response = await fetch(`${thresholdNetworkUrl}/v2/sealoutput`, {
|
|
2884
|
+
method: "POST",
|
|
2885
|
+
headers: {
|
|
2886
|
+
"Content-Type": "application/json"
|
|
2887
|
+
},
|
|
2888
|
+
body: JSON.stringify(body)
|
|
2889
|
+
});
|
|
2890
|
+
} catch (e) {
|
|
2891
|
+
throw new CofheError({
|
|
2892
|
+
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
2893
|
+
message: `sealOutput request failed`,
|
|
2894
|
+
hint: "Ensure the threshold network URL is valid and reachable.",
|
|
2895
|
+
cause: e instanceof Error ? e : void 0,
|
|
2896
|
+
context: {
|
|
2897
|
+
thresholdNetworkUrl,
|
|
2898
|
+
body,
|
|
2899
|
+
attemptIndex
|
|
2900
|
+
}
|
|
2901
|
+
});
|
|
2902
|
+
}
|
|
2903
|
+
if (!response.ok) {
|
|
2904
|
+
let errorMessage = `HTTP ${response.status}`;
|
|
2905
|
+
try {
|
|
2906
|
+
const errorBody = await response.json();
|
|
2907
|
+
errorMessage = errorBody.error_message || errorBody.message || errorMessage;
|
|
2908
|
+
} catch {
|
|
2909
|
+
errorMessage = response.statusText || errorMessage;
|
|
2910
|
+
}
|
|
2911
|
+
throw new CofheError({
|
|
2912
|
+
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
2913
|
+
message: `sealOutput request failed: ${errorMessage}`,
|
|
2914
|
+
hint: "Check the threshold network URL and request parameters.",
|
|
2915
|
+
context: {
|
|
2916
|
+
thresholdNetworkUrl,
|
|
2917
|
+
status: response.status,
|
|
2918
|
+
statusText: response.statusText,
|
|
2919
|
+
body,
|
|
2920
|
+
attemptIndex
|
|
2921
|
+
}
|
|
2922
|
+
});
|
|
2923
|
+
}
|
|
2924
|
+
let submitResponse;
|
|
2925
|
+
if (response.status !== 204) {
|
|
2926
|
+
try {
|
|
2927
|
+
submitResponse = await response.json();
|
|
2928
|
+
} catch (e) {
|
|
2929
|
+
throw new CofheError({
|
|
2930
|
+
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
2931
|
+
message: `Failed to parse sealOutput submit response`,
|
|
2932
|
+
cause: e instanceof Error ? e : void 0,
|
|
2933
|
+
context: {
|
|
2934
|
+
thresholdNetworkUrl,
|
|
2935
|
+
body,
|
|
2936
|
+
attemptIndex
|
|
2937
|
+
}
|
|
2938
|
+
});
|
|
2939
|
+
}
|
|
2940
|
+
if (getSealedDataFromSubmitResponse(submitResponse)) {
|
|
2941
|
+
return {
|
|
2942
|
+
kind: "completed",
|
|
2943
|
+
sealed: parseCompletedSealOutputResponse({
|
|
2944
|
+
value: submitResponse,
|
|
2945
|
+
thresholdNetworkUrl,
|
|
2946
|
+
requestId: submitResponse.request_id
|
|
2947
|
+
})
|
|
2948
|
+
};
|
|
2949
|
+
}
|
|
2950
|
+
if (submitResponse.request_id) {
|
|
2951
|
+
return { kind: "request_id", requestId: submitResponse.request_id };
|
|
2952
|
+
}
|
|
2953
|
+
}
|
|
2954
|
+
if (response.status === 204) {
|
|
2955
|
+
const elapsedMs = Date.now() - overallStartTime;
|
|
2956
|
+
if (elapsedMs > SEAL_OUTPUT_TIMEOUT_MS) {
|
|
2957
|
+
throw new CofheError({
|
|
2958
|
+
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
2959
|
+
message: `sealOutput submit retried without receiving request_id for ${SEAL_OUTPUT_TIMEOUT_MS}ms`,
|
|
2960
|
+
hint: "The ciphertext may still be propagating. Try again later.",
|
|
2961
|
+
context: {
|
|
2962
|
+
thresholdNetworkUrl,
|
|
2963
|
+
body,
|
|
2964
|
+
attemptIndex,
|
|
2965
|
+
timeoutMs: SEAL_OUTPUT_TIMEOUT_MS,
|
|
2966
|
+
submitResponse,
|
|
2967
|
+
status: response.status
|
|
2968
|
+
}
|
|
2969
|
+
});
|
|
2970
|
+
}
|
|
2971
|
+
onPoll?.({
|
|
2972
|
+
operation: "sealoutput",
|
|
2973
|
+
requestId: "",
|
|
2974
|
+
attemptIndex,
|
|
2975
|
+
elapsedMs,
|
|
2976
|
+
intervalMs: SUBMIT_RETRY_INTERVAL_MS,
|
|
2977
|
+
timeoutMs: SEAL_OUTPUT_TIMEOUT_MS
|
|
2978
|
+
});
|
|
2979
|
+
await new Promise((resolve) => setTimeout(resolve, SUBMIT_RETRY_INTERVAL_MS));
|
|
2980
|
+
attemptIndex += 1;
|
|
2981
|
+
continue;
|
|
2982
|
+
}
|
|
2844
2983
|
throw new CofheError({
|
|
2845
2984
|
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
2846
2985
|
message: `sealOutput submit response missing request_id`,
|
|
2847
2986
|
context: {
|
|
2848
2987
|
thresholdNetworkUrl,
|
|
2849
2988
|
body,
|
|
2850
|
-
submitResponse
|
|
2989
|
+
submitResponse,
|
|
2990
|
+
attemptIndex
|
|
2851
2991
|
}
|
|
2852
2992
|
});
|
|
2853
2993
|
}
|
|
2854
|
-
return submitResponse.request_id;
|
|
2855
2994
|
}
|
|
2856
|
-
async function pollSealOutputStatus(thresholdNetworkUrl, requestId) {
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2995
|
+
async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStartTime, onPoll) {
|
|
2996
|
+
let attemptIndex = 0;
|
|
2997
|
+
while (true) {
|
|
2998
|
+
const elapsedMs = Date.now() - overallStartTime;
|
|
2999
|
+
const intervalMs = computeMinuteRampPollIntervalMs(elapsedMs, {
|
|
3000
|
+
minIntervalMs: POLL_INTERVAL_MS,
|
|
3001
|
+
maxIntervalMs: POLL_MAX_INTERVAL_MS
|
|
3002
|
+
});
|
|
3003
|
+
onPoll?.({
|
|
3004
|
+
operation: "sealoutput",
|
|
3005
|
+
requestId,
|
|
3006
|
+
attemptIndex,
|
|
3007
|
+
elapsedMs,
|
|
3008
|
+
intervalMs,
|
|
3009
|
+
timeoutMs: SEAL_OUTPUT_TIMEOUT_MS
|
|
3010
|
+
});
|
|
3011
|
+
if (elapsedMs > SEAL_OUTPUT_TIMEOUT_MS) {
|
|
2861
3012
|
throw new CofheError({
|
|
2862
3013
|
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
2863
|
-
message: `sealOutput polling timed out after ${
|
|
3014
|
+
message: `sealOutput polling timed out after ${SEAL_OUTPUT_TIMEOUT_MS}ms`,
|
|
2864
3015
|
hint: "The request may still be processing. Try again later.",
|
|
2865
3016
|
context: {
|
|
2866
3017
|
thresholdNetworkUrl,
|
|
2867
3018
|
requestId,
|
|
2868
|
-
timeoutMs:
|
|
3019
|
+
timeoutMs: SEAL_OUTPUT_TIMEOUT_MS
|
|
2869
3020
|
}
|
|
2870
3021
|
});
|
|
2871
3022
|
}
|
|
@@ -2934,32 +3085,14 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId) {
|
|
|
2934
3085
|
});
|
|
2935
3086
|
}
|
|
2936
3087
|
if (statusResponse.status === "COMPLETED") {
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
context: {
|
|
2943
|
-
thresholdNetworkUrl,
|
|
2944
|
-
requestId,
|
|
2945
|
-
statusResponse
|
|
2946
|
-
}
|
|
2947
|
-
});
|
|
2948
|
-
}
|
|
2949
|
-
if (!statusResponse.sealed) {
|
|
2950
|
-
throw new CofheError({
|
|
2951
|
-
code: "SEAL_OUTPUT_RETURNED_NULL" /* SealOutputReturnedNull */,
|
|
2952
|
-
message: `sealOutput request completed but returned no sealed data`,
|
|
2953
|
-
context: {
|
|
2954
|
-
thresholdNetworkUrl,
|
|
2955
|
-
requestId,
|
|
2956
|
-
statusResponse
|
|
2957
|
-
}
|
|
2958
|
-
});
|
|
2959
|
-
}
|
|
2960
|
-
return convertSealedData(statusResponse.sealed);
|
|
3088
|
+
return parseCompletedSealOutputResponse({
|
|
3089
|
+
value: statusResponse,
|
|
3090
|
+
thresholdNetworkUrl,
|
|
3091
|
+
requestId
|
|
3092
|
+
});
|
|
2961
3093
|
}
|
|
2962
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
3094
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
3095
|
+
attemptIndex += 1;
|
|
2963
3096
|
}
|
|
2964
3097
|
throw new CofheError({
|
|
2965
3098
|
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
@@ -2970,9 +3103,21 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId) {
|
|
|
2970
3103
|
}
|
|
2971
3104
|
});
|
|
2972
3105
|
}
|
|
2973
|
-
async function tnSealOutputV2(
|
|
2974
|
-
const
|
|
2975
|
-
|
|
3106
|
+
async function tnSealOutputV2(params) {
|
|
3107
|
+
const { thresholdNetworkUrl, ctHash, chainId, permission, onPoll } = params;
|
|
3108
|
+
const overallStartTime = Date.now();
|
|
3109
|
+
const submitResult = await submitSealOutputRequest(
|
|
3110
|
+
thresholdNetworkUrl,
|
|
3111
|
+
ctHash,
|
|
3112
|
+
chainId,
|
|
3113
|
+
permission,
|
|
3114
|
+
overallStartTime,
|
|
3115
|
+
onPoll
|
|
3116
|
+
);
|
|
3117
|
+
if (submitResult.kind === "completed") {
|
|
3118
|
+
return submitResult.sealed;
|
|
3119
|
+
}
|
|
3120
|
+
return await pollSealOutputStatus(thresholdNetworkUrl, submitResult.requestId, overallStartTime, onPoll);
|
|
2976
3121
|
}
|
|
2977
3122
|
|
|
2978
3123
|
// core/decrypt/decryptForViewBuilder.ts
|
|
@@ -2981,6 +3126,7 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
2981
3126
|
utype;
|
|
2982
3127
|
permitHash;
|
|
2983
3128
|
permit;
|
|
3129
|
+
pollCallback;
|
|
2984
3130
|
constructor(params) {
|
|
2985
3131
|
super({
|
|
2986
3132
|
config: params.config,
|
|
@@ -3037,6 +3183,10 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3037
3183
|
getAccount() {
|
|
3038
3184
|
return this.account;
|
|
3039
3185
|
}
|
|
3186
|
+
onPoll(callback) {
|
|
3187
|
+
this.pollCallback = callback;
|
|
3188
|
+
return this;
|
|
3189
|
+
}
|
|
3040
3190
|
withPermit(permitOrPermitHash) {
|
|
3041
3191
|
if (typeof permitOrPermitHash === "string") {
|
|
3042
3192
|
this.permitHash = permitOrPermitHash;
|
|
@@ -3160,7 +3310,13 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3160
3310
|
this.assertPublicClient();
|
|
3161
3311
|
const thresholdNetworkUrl = await this.getThresholdNetworkUrl();
|
|
3162
3312
|
const permission = PermitUtils.getPermission(permit, true);
|
|
3163
|
-
const sealed = await tnSealOutputV2(
|
|
3313
|
+
const sealed = await tnSealOutputV2({
|
|
3314
|
+
ctHash: this.ctHash,
|
|
3315
|
+
chainId: this.chainId,
|
|
3316
|
+
permission,
|
|
3317
|
+
thresholdNetworkUrl,
|
|
3318
|
+
onPoll: this.pollCallback
|
|
3319
|
+
});
|
|
3164
3320
|
return PermitUtils.unseal(permit, sealed);
|
|
3165
3321
|
}
|
|
3166
3322
|
/**
|
|
@@ -3188,7 +3344,6 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3188
3344
|
this.validateUtypeOrThrow();
|
|
3189
3345
|
const permit = await this.getResolvedPermit();
|
|
3190
3346
|
PermitUtils.validate(permit);
|
|
3191
|
-
PermitUtils.isValid(permit);
|
|
3192
3347
|
const chainId = permit._signedDomain.chainId;
|
|
3193
3348
|
let unsealed;
|
|
3194
3349
|
if (chainId === hardhat2.id) {
|
|
@@ -3199,6 +3354,9 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3199
3354
|
return convertViaUtype(this.utype, unsealed);
|
|
3200
3355
|
}
|
|
3201
3356
|
};
|
|
3357
|
+
var UINT_TYPE_MASK = 0x7fn;
|
|
3358
|
+
var TYPE_BYTE_OFFSET = 8n;
|
|
3359
|
+
var getEncryptionTypeFromCtHash = (ctHash) => Number(ctHash >> TYPE_BYTE_OFFSET & UINT_TYPE_MASK);
|
|
3202
3360
|
async function cofheMocksDecryptForTx(ctHash, utype, permit, publicClient) {
|
|
3203
3361
|
let allowed;
|
|
3204
3362
|
let error;
|
|
@@ -3236,7 +3394,13 @@ async function cofheMocksDecryptForTx(ctHash, utype, permit, publicClient) {
|
|
|
3236
3394
|
message: `mocks decryptForTx call failed: ACL Access Denied (NotAllowed)`
|
|
3237
3395
|
});
|
|
3238
3396
|
}
|
|
3239
|
-
const
|
|
3397
|
+
const chainId = publicClient.chain?.id ?? await publicClient.getChainId();
|
|
3398
|
+
const normalizedCtHash = BigInt(ctHash);
|
|
3399
|
+
const encryptionType = getEncryptionTypeFromCtHash(normalizedCtHash);
|
|
3400
|
+
const packed = viem.encodePacked(
|
|
3401
|
+
["uint256", "uint32", "uint64", "uint256"],
|
|
3402
|
+
[decryptedValue, encryptionType, BigInt(chainId), normalizedCtHash]
|
|
3403
|
+
);
|
|
3240
3404
|
const messageHash = viem.keccak256(packed);
|
|
3241
3405
|
const signature = await accounts.sign({
|
|
3242
3406
|
hash: messageHash,
|
|
@@ -3249,7 +3413,7 @@ async function cofheMocksDecryptForTx(ctHash, utype, permit, publicClient) {
|
|
|
3249
3413
|
signature
|
|
3250
3414
|
};
|
|
3251
3415
|
}
|
|
3252
|
-
function
|
|
3416
|
+
function normalizeTnSignature(signature) {
|
|
3253
3417
|
if (typeof signature !== "string") {
|
|
3254
3418
|
throw new CofheError({
|
|
3255
3419
|
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
@@ -3305,141 +3469,384 @@ function parseDecryptedBytesToBigInt(decrypted) {
|
|
|
3305
3469
|
}
|
|
3306
3470
|
return BigInt(`0x${hex}`);
|
|
3307
3471
|
}
|
|
3308
|
-
|
|
3472
|
+
|
|
3473
|
+
// core/decrypt/tnDecryptV2.ts
|
|
3474
|
+
var POLL_INTERVAL_MS2 = 1e3;
|
|
3475
|
+
var POLL_MAX_INTERVAL_MS2 = 1e4;
|
|
3476
|
+
var DECRYPT_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
3477
|
+
var SUBMIT_RETRY_INTERVAL_MS2 = 1e3;
|
|
3478
|
+
function assertDecryptSubmitResponseV2(value) {
|
|
3309
3479
|
if (value == null || typeof value !== "object") {
|
|
3310
3480
|
throw new CofheError({
|
|
3311
3481
|
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3312
|
-
message: "decrypt response must be a JSON object",
|
|
3482
|
+
message: "decrypt submit response must be a JSON object",
|
|
3313
3483
|
context: {
|
|
3314
3484
|
value
|
|
3315
3485
|
}
|
|
3316
3486
|
});
|
|
3317
3487
|
}
|
|
3318
3488
|
const v = value;
|
|
3319
|
-
|
|
3320
|
-
const signature = v.signature;
|
|
3321
|
-
const encryptionType = v.encryption_type;
|
|
3322
|
-
const errorMessage = v.error_message;
|
|
3323
|
-
if (!Array.isArray(decrypted)) {
|
|
3489
|
+
if (v.request_id !== null && typeof v.request_id !== "string") {
|
|
3324
3490
|
throw new CofheError({
|
|
3325
|
-
code: "
|
|
3326
|
-
message: "decrypt response
|
|
3327
|
-
context: {
|
|
3491
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3492
|
+
message: "decrypt submit response has invalid request_id",
|
|
3493
|
+
context: {
|
|
3494
|
+
value
|
|
3495
|
+
}
|
|
3328
3496
|
});
|
|
3329
3497
|
}
|
|
3330
|
-
|
|
3498
|
+
return {
|
|
3499
|
+
request_id: v.request_id ?? null,
|
|
3500
|
+
status: typeof v.status === "string" ? v.status : void 0,
|
|
3501
|
+
is_succeed: typeof v.is_succeed === "boolean" ? v.is_succeed : void 0,
|
|
3502
|
+
decrypted: Array.isArray(v.decrypted) ? v.decrypted : void 0,
|
|
3503
|
+
signature: typeof v.signature === "string" ? v.signature : void 0,
|
|
3504
|
+
encryption_type: typeof v.encryption_type === "number" ? v.encryption_type : void 0,
|
|
3505
|
+
error_message: typeof v.error_message === "string" || v.error_message === null ? v.error_message : void 0,
|
|
3506
|
+
message: typeof v.message === "string" ? v.message : void 0
|
|
3507
|
+
};
|
|
3508
|
+
}
|
|
3509
|
+
function parseCompletedDecryptResponseV2(params) {
|
|
3510
|
+
const { value, thresholdNetworkUrl, requestId } = params;
|
|
3511
|
+
if (value.is_succeed === false) {
|
|
3512
|
+
const errorMessage = value.error_message || "Unknown error";
|
|
3331
3513
|
throw new CofheError({
|
|
3332
|
-
code: "
|
|
3333
|
-
message:
|
|
3334
|
-
context: {
|
|
3514
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3515
|
+
message: `decrypt request failed: ${errorMessage}`,
|
|
3516
|
+
context: {
|
|
3517
|
+
thresholdNetworkUrl,
|
|
3518
|
+
requestId,
|
|
3519
|
+
response: value
|
|
3520
|
+
}
|
|
3335
3521
|
});
|
|
3336
3522
|
}
|
|
3337
|
-
if (
|
|
3523
|
+
if (value.error_message) {
|
|
3338
3524
|
throw new CofheError({
|
|
3339
3525
|
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3340
|
-
message:
|
|
3341
|
-
context: {
|
|
3526
|
+
message: `decrypt request failed: ${value.error_message}`,
|
|
3527
|
+
context: {
|
|
3528
|
+
thresholdNetworkUrl,
|
|
3529
|
+
requestId,
|
|
3530
|
+
response: value
|
|
3531
|
+
}
|
|
3342
3532
|
});
|
|
3343
3533
|
}
|
|
3344
|
-
if (!(
|
|
3534
|
+
if (!Array.isArray(value.decrypted)) {
|
|
3345
3535
|
throw new CofheError({
|
|
3346
|
-
code: "
|
|
3347
|
-
message: "decrypt response
|
|
3348
|
-
context: {
|
|
3536
|
+
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3537
|
+
message: "decrypt completed but response missing <decrypted> byte array",
|
|
3538
|
+
context: {
|
|
3539
|
+
thresholdNetworkUrl,
|
|
3540
|
+
requestId,
|
|
3541
|
+
response: value
|
|
3542
|
+
}
|
|
3349
3543
|
});
|
|
3350
3544
|
}
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
encryption_type: encryptionType,
|
|
3355
|
-
error_message: errorMessage
|
|
3356
|
-
};
|
|
3545
|
+
const decryptedValue = parseDecryptedBytesToBigInt(value.decrypted);
|
|
3546
|
+
const signature = normalizeTnSignature(value.signature);
|
|
3547
|
+
return { decryptedValue, signature };
|
|
3357
3548
|
}
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
let response;
|
|
3367
|
-
try {
|
|
3368
|
-
response = await fetch(`${thresholdNetworkUrl}/decrypt`, {
|
|
3369
|
-
method: "POST",
|
|
3370
|
-
headers: {
|
|
3371
|
-
"Content-Type": "application/json"
|
|
3372
|
-
},
|
|
3373
|
-
body: JSON.stringify(body)
|
|
3549
|
+
function assertDecryptStatusResponseV2(value) {
|
|
3550
|
+
if (value == null || typeof value !== "object") {
|
|
3551
|
+
throw new CofheError({
|
|
3552
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3553
|
+
message: "decrypt status response must be a JSON object",
|
|
3554
|
+
context: {
|
|
3555
|
+
value
|
|
3556
|
+
}
|
|
3374
3557
|
});
|
|
3375
|
-
}
|
|
3558
|
+
}
|
|
3559
|
+
const v = value;
|
|
3560
|
+
const requestId = v.request_id;
|
|
3561
|
+
const status = v.status;
|
|
3562
|
+
const submittedAt = v.submitted_at;
|
|
3563
|
+
if (typeof requestId !== "string" || requestId.trim().length === 0) {
|
|
3376
3564
|
throw new CofheError({
|
|
3377
3565
|
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3378
|
-
message:
|
|
3379
|
-
hint: "Ensure the threshold network URL is valid and reachable.",
|
|
3380
|
-
cause: e instanceof Error ? e : void 0,
|
|
3566
|
+
message: "decrypt status response missing request_id",
|
|
3381
3567
|
context: {
|
|
3382
|
-
|
|
3383
|
-
body
|
|
3568
|
+
value
|
|
3384
3569
|
}
|
|
3385
3570
|
});
|
|
3386
3571
|
}
|
|
3387
|
-
|
|
3388
|
-
if (!response.ok) {
|
|
3389
|
-
let errorMessage = response.statusText || `HTTP ${response.status}`;
|
|
3390
|
-
try {
|
|
3391
|
-
const errorBody = JSON.parse(responseText);
|
|
3392
|
-
const maybeMessage = errorBody.error_message || errorBody.message;
|
|
3393
|
-
if (typeof maybeMessage === "string" && maybeMessage.length > 0)
|
|
3394
|
-
errorMessage = maybeMessage;
|
|
3395
|
-
} catch {
|
|
3396
|
-
const trimmed = responseText.trim();
|
|
3397
|
-
if (trimmed.length > 0)
|
|
3398
|
-
errorMessage = trimmed;
|
|
3399
|
-
}
|
|
3572
|
+
if (status !== "PROCESSING" && status !== "COMPLETED") {
|
|
3400
3573
|
throw new CofheError({
|
|
3401
3574
|
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3402
|
-
message:
|
|
3403
|
-
hint: "Check the threshold network URL and request parameters.",
|
|
3575
|
+
message: "decrypt status response has invalid status",
|
|
3404
3576
|
context: {
|
|
3405
|
-
|
|
3406
|
-
status
|
|
3407
|
-
statusText: response.statusText,
|
|
3408
|
-
body,
|
|
3409
|
-
responseText
|
|
3577
|
+
value,
|
|
3578
|
+
status
|
|
3410
3579
|
}
|
|
3411
3580
|
});
|
|
3412
3581
|
}
|
|
3413
|
-
|
|
3414
|
-
try {
|
|
3415
|
-
rawJson = JSON.parse(responseText);
|
|
3416
|
-
} catch (e) {
|
|
3582
|
+
if (typeof submittedAt !== "string" || submittedAt.trim().length === 0) {
|
|
3417
3583
|
throw new CofheError({
|
|
3418
3584
|
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3419
|
-
message:
|
|
3420
|
-
cause: e instanceof Error ? e : void 0,
|
|
3585
|
+
message: "decrypt status response missing submitted_at",
|
|
3421
3586
|
context: {
|
|
3422
|
-
|
|
3423
|
-
body,
|
|
3424
|
-
responseText
|
|
3587
|
+
value
|
|
3425
3588
|
}
|
|
3426
3589
|
});
|
|
3427
3590
|
}
|
|
3428
|
-
|
|
3429
|
-
|
|
3591
|
+
return value;
|
|
3592
|
+
}
|
|
3593
|
+
async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, permission, overallStartTime, onPoll) {
|
|
3594
|
+
const body = {
|
|
3595
|
+
ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
|
|
3596
|
+
host_chain_id: chainId
|
|
3597
|
+
};
|
|
3598
|
+
if (permission) {
|
|
3599
|
+
body.permit = permission;
|
|
3600
|
+
}
|
|
3601
|
+
let attemptIndex = 0;
|
|
3602
|
+
for (; ; ) {
|
|
3603
|
+
let response;
|
|
3604
|
+
try {
|
|
3605
|
+
response = await fetch(`${thresholdNetworkUrl}/v2/decrypt`, {
|
|
3606
|
+
method: "POST",
|
|
3607
|
+
headers: {
|
|
3608
|
+
"Content-Type": "application/json"
|
|
3609
|
+
},
|
|
3610
|
+
body: JSON.stringify(body)
|
|
3611
|
+
});
|
|
3612
|
+
} catch (e) {
|
|
3613
|
+
throw new CofheError({
|
|
3614
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3615
|
+
message: `decrypt request failed`,
|
|
3616
|
+
hint: "Ensure the threshold network URL is valid and reachable.",
|
|
3617
|
+
cause: e instanceof Error ? e : void 0,
|
|
3618
|
+
context: {
|
|
3619
|
+
thresholdNetworkUrl,
|
|
3620
|
+
body,
|
|
3621
|
+
attemptIndex
|
|
3622
|
+
}
|
|
3623
|
+
});
|
|
3624
|
+
}
|
|
3625
|
+
if (!response.ok) {
|
|
3626
|
+
let errorMessage = `HTTP ${response.status}`;
|
|
3627
|
+
try {
|
|
3628
|
+
const errorBody = await response.json();
|
|
3629
|
+
const maybeMessage = errorBody.error_message || errorBody.message;
|
|
3630
|
+
if (typeof maybeMessage === "string" && maybeMessage.length > 0)
|
|
3631
|
+
errorMessage = maybeMessage;
|
|
3632
|
+
} catch {
|
|
3633
|
+
errorMessage = response.statusText || errorMessage;
|
|
3634
|
+
}
|
|
3635
|
+
throw new CofheError({
|
|
3636
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3637
|
+
message: `decrypt request failed: ${errorMessage}`,
|
|
3638
|
+
hint: "Check the threshold network URL and request parameters.",
|
|
3639
|
+
context: {
|
|
3640
|
+
thresholdNetworkUrl,
|
|
3641
|
+
status: response.status,
|
|
3642
|
+
statusText: response.statusText,
|
|
3643
|
+
body,
|
|
3644
|
+
attemptIndex
|
|
3645
|
+
}
|
|
3646
|
+
});
|
|
3647
|
+
}
|
|
3648
|
+
let submitResponse;
|
|
3649
|
+
if (response.status !== 204) {
|
|
3650
|
+
let rawJson;
|
|
3651
|
+
try {
|
|
3652
|
+
rawJson = await response.json();
|
|
3653
|
+
} catch (e) {
|
|
3654
|
+
throw new CofheError({
|
|
3655
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3656
|
+
message: `Failed to parse decrypt submit response`,
|
|
3657
|
+
cause: e instanceof Error ? e : void 0,
|
|
3658
|
+
context: {
|
|
3659
|
+
thresholdNetworkUrl,
|
|
3660
|
+
body,
|
|
3661
|
+
attemptIndex
|
|
3662
|
+
}
|
|
3663
|
+
});
|
|
3664
|
+
}
|
|
3665
|
+
submitResponse = assertDecryptSubmitResponseV2(rawJson);
|
|
3666
|
+
if (Array.isArray(submitResponse.decrypted) && typeof submitResponse.signature === "string") {
|
|
3667
|
+
return {
|
|
3668
|
+
kind: "completed",
|
|
3669
|
+
...parseCompletedDecryptResponseV2({
|
|
3670
|
+
value: submitResponse,
|
|
3671
|
+
thresholdNetworkUrl,
|
|
3672
|
+
requestId: submitResponse.request_id
|
|
3673
|
+
})
|
|
3674
|
+
};
|
|
3675
|
+
}
|
|
3676
|
+
if (submitResponse.request_id) {
|
|
3677
|
+
return { kind: "request_id", requestId: submitResponse.request_id };
|
|
3678
|
+
}
|
|
3679
|
+
}
|
|
3680
|
+
if (response.status === 204) {
|
|
3681
|
+
const elapsedMs = Date.now() - overallStartTime;
|
|
3682
|
+
if (elapsedMs > DECRYPT_TIMEOUT_MS) {
|
|
3683
|
+
throw new CofheError({
|
|
3684
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3685
|
+
message: `decrypt submit retried without receiving request_id for ${DECRYPT_TIMEOUT_MS}ms`,
|
|
3686
|
+
hint: "The ciphertext may still be propagating. Try again later.",
|
|
3687
|
+
context: {
|
|
3688
|
+
thresholdNetworkUrl,
|
|
3689
|
+
body,
|
|
3690
|
+
attemptIndex,
|
|
3691
|
+
timeoutMs: DECRYPT_TIMEOUT_MS,
|
|
3692
|
+
submitResponse,
|
|
3693
|
+
status: response.status
|
|
3694
|
+
}
|
|
3695
|
+
});
|
|
3696
|
+
}
|
|
3697
|
+
onPoll?.({
|
|
3698
|
+
operation: "decrypt",
|
|
3699
|
+
requestId: "",
|
|
3700
|
+
attemptIndex,
|
|
3701
|
+
elapsedMs,
|
|
3702
|
+
intervalMs: SUBMIT_RETRY_INTERVAL_MS2,
|
|
3703
|
+
timeoutMs: DECRYPT_TIMEOUT_MS
|
|
3704
|
+
});
|
|
3705
|
+
await new Promise((resolve) => setTimeout(resolve, SUBMIT_RETRY_INTERVAL_MS2));
|
|
3706
|
+
attemptIndex += 1;
|
|
3707
|
+
continue;
|
|
3708
|
+
}
|
|
3430
3709
|
throw new CofheError({
|
|
3431
3710
|
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3432
|
-
message: `decrypt
|
|
3711
|
+
message: `decrypt submit response missing request_id`,
|
|
3433
3712
|
context: {
|
|
3434
3713
|
thresholdNetworkUrl,
|
|
3435
3714
|
body,
|
|
3436
|
-
|
|
3715
|
+
submitResponse,
|
|
3716
|
+
attemptIndex
|
|
3437
3717
|
}
|
|
3438
3718
|
});
|
|
3439
3719
|
}
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3720
|
+
}
|
|
3721
|
+
async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartTime, onPoll) {
|
|
3722
|
+
let attemptIndex = 0;
|
|
3723
|
+
while (true) {
|
|
3724
|
+
const elapsedMs = Date.now() - overallStartTime;
|
|
3725
|
+
const intervalMs = computeMinuteRampPollIntervalMs(elapsedMs, {
|
|
3726
|
+
minIntervalMs: POLL_INTERVAL_MS2,
|
|
3727
|
+
maxIntervalMs: POLL_MAX_INTERVAL_MS2
|
|
3728
|
+
});
|
|
3729
|
+
onPoll?.({
|
|
3730
|
+
operation: "decrypt",
|
|
3731
|
+
requestId,
|
|
3732
|
+
attemptIndex,
|
|
3733
|
+
elapsedMs,
|
|
3734
|
+
intervalMs,
|
|
3735
|
+
timeoutMs: DECRYPT_TIMEOUT_MS
|
|
3736
|
+
});
|
|
3737
|
+
if (elapsedMs > DECRYPT_TIMEOUT_MS) {
|
|
3738
|
+
throw new CofheError({
|
|
3739
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3740
|
+
message: `decrypt polling timed out after ${DECRYPT_TIMEOUT_MS}ms`,
|
|
3741
|
+
hint: "The request may still be processing. Try again later.",
|
|
3742
|
+
context: {
|
|
3743
|
+
thresholdNetworkUrl,
|
|
3744
|
+
requestId,
|
|
3745
|
+
timeoutMs: DECRYPT_TIMEOUT_MS
|
|
3746
|
+
}
|
|
3747
|
+
});
|
|
3748
|
+
}
|
|
3749
|
+
let response;
|
|
3750
|
+
try {
|
|
3751
|
+
response = await fetch(`${thresholdNetworkUrl}/v2/decrypt/${requestId}`, {
|
|
3752
|
+
method: "GET",
|
|
3753
|
+
headers: {
|
|
3754
|
+
"Content-Type": "application/json"
|
|
3755
|
+
}
|
|
3756
|
+
});
|
|
3757
|
+
} catch (e) {
|
|
3758
|
+
throw new CofheError({
|
|
3759
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3760
|
+
message: `decrypt status poll failed`,
|
|
3761
|
+
hint: "Ensure the threshold network URL is valid and reachable.",
|
|
3762
|
+
cause: e instanceof Error ? e : void 0,
|
|
3763
|
+
context: {
|
|
3764
|
+
thresholdNetworkUrl,
|
|
3765
|
+
requestId
|
|
3766
|
+
}
|
|
3767
|
+
});
|
|
3768
|
+
}
|
|
3769
|
+
if (response.status === 404) {
|
|
3770
|
+
throw new CofheError({
|
|
3771
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3772
|
+
message: `decrypt request not found: ${requestId}`,
|
|
3773
|
+
hint: "The request may have expired or been invalid.",
|
|
3774
|
+
context: {
|
|
3775
|
+
thresholdNetworkUrl,
|
|
3776
|
+
requestId
|
|
3777
|
+
}
|
|
3778
|
+
});
|
|
3779
|
+
}
|
|
3780
|
+
if (!response.ok) {
|
|
3781
|
+
let errorMessage = `HTTP ${response.status}`;
|
|
3782
|
+
try {
|
|
3783
|
+
const errorBody = await response.json();
|
|
3784
|
+
const maybeMessage = errorBody.error_message || errorBody.message;
|
|
3785
|
+
if (typeof maybeMessage === "string" && maybeMessage.length > 0)
|
|
3786
|
+
errorMessage = maybeMessage;
|
|
3787
|
+
} catch {
|
|
3788
|
+
errorMessage = response.statusText || errorMessage;
|
|
3789
|
+
}
|
|
3790
|
+
throw new CofheError({
|
|
3791
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3792
|
+
message: `decrypt status poll failed: ${errorMessage}`,
|
|
3793
|
+
context: {
|
|
3794
|
+
thresholdNetworkUrl,
|
|
3795
|
+
requestId,
|
|
3796
|
+
status: response.status,
|
|
3797
|
+
statusText: response.statusText
|
|
3798
|
+
}
|
|
3799
|
+
});
|
|
3800
|
+
}
|
|
3801
|
+
let rawJson;
|
|
3802
|
+
try {
|
|
3803
|
+
rawJson = await response.json();
|
|
3804
|
+
} catch (e) {
|
|
3805
|
+
throw new CofheError({
|
|
3806
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3807
|
+
message: `Failed to parse decrypt status response`,
|
|
3808
|
+
cause: e instanceof Error ? e : void 0,
|
|
3809
|
+
context: {
|
|
3810
|
+
thresholdNetworkUrl,
|
|
3811
|
+
requestId
|
|
3812
|
+
}
|
|
3813
|
+
});
|
|
3814
|
+
}
|
|
3815
|
+
const statusResponse = assertDecryptStatusResponseV2(rawJson);
|
|
3816
|
+
if (statusResponse.status === "COMPLETED") {
|
|
3817
|
+
return parseCompletedDecryptResponseV2({
|
|
3818
|
+
value: statusResponse,
|
|
3819
|
+
thresholdNetworkUrl,
|
|
3820
|
+
requestId
|
|
3821
|
+
});
|
|
3822
|
+
}
|
|
3823
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
3824
|
+
attemptIndex += 1;
|
|
3825
|
+
}
|
|
3826
|
+
throw new CofheError({
|
|
3827
|
+
code: "DECRYPT_FAILED" /* DecryptFailed */,
|
|
3828
|
+
message: "Polling loop exited unexpectedly",
|
|
3829
|
+
context: {
|
|
3830
|
+
thresholdNetworkUrl,
|
|
3831
|
+
requestId
|
|
3832
|
+
}
|
|
3833
|
+
});
|
|
3834
|
+
}
|
|
3835
|
+
async function tnDecryptV2(params) {
|
|
3836
|
+
const { thresholdNetworkUrl, ctHash, chainId, permission, onPoll } = params;
|
|
3837
|
+
const overallStartTime = Date.now();
|
|
3838
|
+
const submitResult = await submitDecryptRequestV2(
|
|
3839
|
+
thresholdNetworkUrl,
|
|
3840
|
+
ctHash,
|
|
3841
|
+
chainId,
|
|
3842
|
+
permission,
|
|
3843
|
+
overallStartTime,
|
|
3844
|
+
onPoll
|
|
3845
|
+
);
|
|
3846
|
+
if (submitResult.kind === "completed") {
|
|
3847
|
+
return submitResult;
|
|
3848
|
+
}
|
|
3849
|
+
return await pollDecryptStatusV2(thresholdNetworkUrl, submitResult.requestId, overallStartTime, onPoll);
|
|
3443
3850
|
}
|
|
3444
3851
|
|
|
3445
3852
|
// core/decrypt/decryptForTxBuilder.ts
|
|
@@ -3448,6 +3855,7 @@ var DecryptForTxBuilder = class extends BaseBuilder {
|
|
|
3448
3855
|
permitHash;
|
|
3449
3856
|
permit;
|
|
3450
3857
|
permitSelection = "unset";
|
|
3858
|
+
pollCallback;
|
|
3451
3859
|
constructor(params) {
|
|
3452
3860
|
super({
|
|
3453
3861
|
config: params.config,
|
|
@@ -3473,6 +3881,10 @@ var DecryptForTxBuilder = class extends BaseBuilder {
|
|
|
3473
3881
|
getAccount() {
|
|
3474
3882
|
return this.account;
|
|
3475
3883
|
}
|
|
3884
|
+
onPoll(callback) {
|
|
3885
|
+
this.pollCallback = callback;
|
|
3886
|
+
return this;
|
|
3887
|
+
}
|
|
3476
3888
|
withPermit(permitOrPermitHash) {
|
|
3477
3889
|
if (this.permitSelection === "with-permit") {
|
|
3478
3890
|
throw new CofheError({
|
|
@@ -3600,7 +4012,13 @@ var DecryptForTxBuilder = class extends BaseBuilder {
|
|
|
3600
4012
|
this.assertPublicClient();
|
|
3601
4013
|
const thresholdNetworkUrl = await this.getThresholdNetworkUrl();
|
|
3602
4014
|
const permission = permit ? PermitUtils.getPermission(permit, true) : null;
|
|
3603
|
-
const { decryptedValue, signature } = await
|
|
4015
|
+
const { decryptedValue, signature } = await tnDecryptV2({
|
|
4016
|
+
ctHash: this.ctHash,
|
|
4017
|
+
chainId: this.chainId,
|
|
4018
|
+
permission,
|
|
4019
|
+
thresholdNetworkUrl,
|
|
4020
|
+
onPoll: this.pollCallback
|
|
4021
|
+
});
|
|
3604
4022
|
return {
|
|
3605
4023
|
ctHash: this.ctHash,
|
|
3606
4024
|
decryptedValue,
|
|
@@ -3618,7 +4036,6 @@ var DecryptForTxBuilder = class extends BaseBuilder {
|
|
|
3618
4036
|
const permit = await this.getResolvedPermit();
|
|
3619
4037
|
if (permit !== null) {
|
|
3620
4038
|
PermitUtils.validate(permit);
|
|
3621
|
-
PermitUtils.isValid(permit);
|
|
3622
4039
|
const chainId = permit._signedDomain.chainId;
|
|
3623
4040
|
if (chainId === hardhat2.id) {
|
|
3624
4041
|
return await this.mocksDecryptForTx(permit);
|
|
@@ -3639,6 +4056,35 @@ var DecryptForTxBuilder = class extends BaseBuilder {
|
|
|
3639
4056
|
}
|
|
3640
4057
|
}
|
|
3641
4058
|
};
|
|
4059
|
+
var decryptResultSignerAbi = viem.parseAbi(["function decryptResultSigner() view returns (address)"]);
|
|
4060
|
+
var UINT_TYPE_MASK2 = 0x7fn;
|
|
4061
|
+
var TYPE_BYTE_OFFSET2 = 8n;
|
|
4062
|
+
var getEncryptionTypeFromCtHash2 = (ctHash) => Number(ctHash >> TYPE_BYTE_OFFSET2 & UINT_TYPE_MASK2);
|
|
4063
|
+
var buildDecryptResultHash = (ctHash, cleartext, chainId) => {
|
|
4064
|
+
const encryptionType = getEncryptionTypeFromCtHash2(ctHash);
|
|
4065
|
+
return viem.keccak256(
|
|
4066
|
+
viem.encodePacked(["uint256", "uint32", "uint64", "uint256"], [cleartext, encryptionType, BigInt(chainId), ctHash])
|
|
4067
|
+
);
|
|
4068
|
+
};
|
|
4069
|
+
async function verifyDecryptResult(handle, cleartext, signature, publicClient) {
|
|
4070
|
+
const chainId = publicClient.chain?.id ?? await publicClient.getChainId();
|
|
4071
|
+
const expectedSigner = await publicClient.readContract({
|
|
4072
|
+
address: TASK_MANAGER_ADDRESS,
|
|
4073
|
+
abi: decryptResultSignerAbi,
|
|
4074
|
+
functionName: "decryptResultSigner",
|
|
4075
|
+
args: []
|
|
4076
|
+
});
|
|
4077
|
+
if (viem.isAddressEqual(expectedSigner, viem.zeroAddress))
|
|
4078
|
+
return true;
|
|
4079
|
+
const ctHash = BigInt(handle);
|
|
4080
|
+
const messageHash = buildDecryptResultHash(ctHash, cleartext, chainId);
|
|
4081
|
+
try {
|
|
4082
|
+
const recovered = await viem.recoverAddress({ hash: messageHash, signature });
|
|
4083
|
+
return viem.isAddressEqual(recovered, expectedSigner);
|
|
4084
|
+
} catch {
|
|
4085
|
+
return false;
|
|
4086
|
+
}
|
|
4087
|
+
}
|
|
3642
4088
|
|
|
3643
4089
|
// core/client.ts
|
|
3644
4090
|
var InitialConnectStore = {
|
|
@@ -3757,6 +4203,11 @@ function createCofheClientBase(opts) {
|
|
|
3757
4203
|
requireConnected: _requireConnected
|
|
3758
4204
|
});
|
|
3759
4205
|
}
|
|
4206
|
+
function verifyDecryptResult2(handle, cleartext, signature) {
|
|
4207
|
+
_requireConnected();
|
|
4208
|
+
const { publicClient } = connectStore.getState();
|
|
4209
|
+
return verifyDecryptResult(handle, cleartext, signature, publicClient);
|
|
4210
|
+
}
|
|
3760
4211
|
const _getChainIdAndAccount = (chainId, account) => {
|
|
3761
4212
|
const state = connectStore.getState();
|
|
3762
4213
|
const _chainId = chainId ?? state.chainId;
|
|
@@ -3808,19 +4259,19 @@ function createCofheClientBase(opts) {
|
|
|
3808
4259
|
return permits.getOrCreateSharingPermit(publicClient, walletClient, options, _chainId, _account);
|
|
3809
4260
|
},
|
|
3810
4261
|
// Retrieval methods (auto-fill chainId/account)
|
|
3811
|
-
getPermit:
|
|
4262
|
+
getPermit: (hash, chainId, account) => {
|
|
3812
4263
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
3813
4264
|
return permits.getPermit(_chainId, _account, hash);
|
|
3814
4265
|
},
|
|
3815
|
-
getPermits:
|
|
4266
|
+
getPermits: (chainId, account) => {
|
|
3816
4267
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
3817
4268
|
return permits.getPermits(_chainId, _account);
|
|
3818
4269
|
},
|
|
3819
|
-
getActivePermit:
|
|
4270
|
+
getActivePermit: (chainId, account) => {
|
|
3820
4271
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
3821
4272
|
return permits.getActivePermit(_chainId, _account);
|
|
3822
4273
|
},
|
|
3823
|
-
getActivePermitHash:
|
|
4274
|
+
getActivePermitHash: (chainId, account) => {
|
|
3824
4275
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
3825
4276
|
return permits.getActivePermitHash(_chainId, _account);
|
|
3826
4277
|
},
|
|
@@ -3839,6 +4290,7 @@ function createCofheClientBase(opts) {
|
|
|
3839
4290
|
},
|
|
3840
4291
|
// Utils (no context needed)
|
|
3841
4292
|
getHash: permits.getHash,
|
|
4293
|
+
export: permits.export,
|
|
3842
4294
|
serialize: permits.serialize,
|
|
3843
4295
|
deserialize: permits.deserialize
|
|
3844
4296
|
};
|
|
@@ -3867,6 +4319,7 @@ function createCofheClientBase(opts) {
|
|
|
3867
4319
|
*/
|
|
3868
4320
|
decryptHandle: decryptForView,
|
|
3869
4321
|
decryptForTx,
|
|
4322
|
+
verifyDecryptResult: verifyDecryptResult2,
|
|
3870
4323
|
permits: clientPermits
|
|
3871
4324
|
// Add SDK-specific methods below that require connection
|
|
3872
4325
|
// Example:
|
|
@@ -3930,16 +4383,22 @@ var fromHexString2 = (hexString) => {
|
|
|
3930
4383
|
return new Uint8Array();
|
|
3931
4384
|
return new Uint8Array(arr.map((byte) => parseInt(byte, 16)));
|
|
3932
4385
|
};
|
|
4386
|
+
var _deserializeTfhePublicKey = (buff) => {
|
|
4387
|
+
return nodeTfhe.TfheCompactPublicKey.safe_deserialize(fromHexString2(buff), TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
|
|
4388
|
+
};
|
|
4389
|
+
var _deserializeCompactPkeCrs = (buff) => {
|
|
4390
|
+
return nodeTfhe.CompactPkeCrs.safe_deserialize(fromHexString2(buff), TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
|
|
4391
|
+
};
|
|
3933
4392
|
var tfhePublicKeyDeserializer = (buff) => {
|
|
3934
|
-
|
|
4393
|
+
_deserializeTfhePublicKey(buff);
|
|
3935
4394
|
};
|
|
3936
4395
|
var compactPkeCrsDeserializer = (buff) => {
|
|
3937
|
-
|
|
4396
|
+
_deserializeCompactPkeCrs(buff);
|
|
3938
4397
|
};
|
|
3939
4398
|
var zkBuilderAndCrsGenerator = (fhe, crs) => {
|
|
3940
|
-
const fhePublicKey =
|
|
4399
|
+
const fhePublicKey = _deserializeTfhePublicKey(fhe);
|
|
3941
4400
|
const zkBuilder = nodeTfhe.ProvenCompactCiphertextList.builder(fhePublicKey);
|
|
3942
|
-
const zkCrs =
|
|
4401
|
+
const zkCrs = _deserializeCompactPkeCrs(crs);
|
|
3943
4402
|
return { zkBuilder, zkCrs };
|
|
3944
4403
|
};
|
|
3945
4404
|
function createCofheConfig(config) {
|