@cofhe/sdk 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/acps/acp.ts +10 -1
  3. package/acps/index.ts +11 -0
  4. package/acps/onchain-utils.ts +188 -49
  5. package/acps/registry.ts +73 -0
  6. package/acps/test/onchainAccessStatus.test.ts +116 -0
  7. package/acps/types.ts +16 -0
  8. package/chains/chains/arbitrum.ts +14 -0
  9. package/chains/chains/ethereum.ts +14 -0
  10. package/chains/index.ts +5 -1
  11. package/chains/test/chains.test.ts +24 -3
  12. package/core/acps.ts +51 -143
  13. package/core/client.ts +13 -8
  14. package/core/clientTypes.ts +29 -4
  15. package/core/config.ts +25 -1
  16. package/core/consts.ts +14 -2
  17. package/core/decrypt/verifyDecryptResult.ts +4 -3
  18. package/core/encrypt/encryptInputsBuilder.ts +6 -0
  19. package/core/encrypt/zkPackProveVerify.ts +7 -1
  20. package/core/error.ts +1 -0
  21. package/core/fetchKeys.ts +2 -2
  22. package/core/index.ts +9 -1
  23. package/core/keyStore.ts +23 -10
  24. package/core/taskManager.ts +48 -0
  25. package/core/test/acps.test.ts +91 -1
  26. package/core/test/client.test.ts +41 -0
  27. package/core/test/config.test.ts +16 -0
  28. package/core/test/decrypt.test.ts +11 -4
  29. package/core/test/encryptInputsBuilder.test.ts +1 -1
  30. package/core/test/fetchKeys.test.ts +23 -2
  31. package/core/test/keyStore.test.ts +18 -6
  32. package/core/test/taskManager.test.ts +57 -0
  33. package/core/types.ts +8 -0
  34. package/dist/acps.cjs +314 -35
  35. package/dist/acps.d.cts +251 -4
  36. package/dist/acps.d.ts +251 -4
  37. package/dist/acps.js +2 -2
  38. package/dist/chains.cjs +26 -0
  39. package/dist/chains.d.cts +45 -1
  40. package/dist/chains.d.ts +45 -1
  41. package/dist/chains.js +1 -1
  42. package/dist/{chunk-43USWPEH.js → chunk-GGI7Y6AW.js} +59 -264
  43. package/dist/chunk-KSOV5B4B.js +50 -0
  44. package/dist/{chunk-ESMZCFJY.js → chunk-NMKMCAI3.js} +4 -2
  45. package/dist/{chunk-Q7CBWGQX.js → chunk-UJYOBHYA.js} +374 -37
  46. package/dist/{chunk-N6IDQRRU.js → chunk-UKQAJK4N.js} +25 -1
  47. package/dist/{clientTypes-BN3nbzYM.d.ts → clientTypes-5YPPR16m.d.ts} +77 -14
  48. package/dist/{clientTypes-CYZjFznO.d.cts → clientTypes-D3aIXmUp.d.cts} +77 -14
  49. package/dist/core.cjs +271 -136
  50. package/dist/core.d.cts +29 -8
  51. package/dist/core.d.ts +29 -8
  52. package/dist/core.js +4 -4
  53. package/dist/node.cjs +266 -136
  54. package/dist/node.d.cts +2 -2
  55. package/dist/node.d.ts +2 -2
  56. package/dist/node.js +5 -5
  57. package/dist/{acp-Wi6isVQI.d.cts → onchain-utils-CUAK8glx.d.cts} +31 -1
  58. package/dist/{acp-Wi6isVQI.d.ts → onchain-utils-CUAK8glx.d.ts} +31 -1
  59. package/dist/web.cjs +360 -150
  60. package/dist/web.d.cts +49 -3
  61. package/dist/web.d.ts +49 -3
  62. package/dist/web.js +51 -20
  63. package/dist/zkProve.worker.cjs +69 -15
  64. package/dist/zkProve.worker.js +23 -17
  65. package/node/storage.ts +2 -2
  66. package/node/test/inherited.test.ts +5 -1
  67. package/node/test/storage-memory-fallback.test.ts +47 -0
  68. package/package.json +5 -3
  69. package/web/index.ts +100 -26
  70. package/web/test/countingZkProveWorker.ts +31 -0
  71. package/web/test/inherited.web.test.ts +5 -1
  72. package/web/test/mainThreadPool.web.test.ts +174 -0
  73. package/web/test/threadPoolBenchHelper.ts +140 -0
  74. package/web/test/threadPoolOff.web.test.ts +17 -0
  75. package/web/test/threadPoolOn.web.test.ts +80 -0
  76. package/web/test/workerInitRace.web.test.ts +79 -0
  77. package/web/tfheThreadPool.ts +140 -0
  78. package/web/workerManager.ts +4 -2
  79. package/web/zkProve.worker.ts +42 -17
package/dist/web.cjs CHANGED
@@ -112,7 +112,8 @@ var bigintSafeJsonStringify = (value) => {
112
112
  var isCofheError = (error) => error instanceof CofheError;
113
113
 
114
114
  // core/consts.ts
115
- var TASK_MANAGER_ADDRESS = "0xeA30c4B8b44078Bbf8a6ef5b9f1eC1626C7848D9";
115
+ var COFHE_ADDRESS_BOOK_ADDRESS = "0xC0F4e00E531a2B086492Ae3DCC1515038307196b";
116
+ var TASK_MANAGER_ID = 1n;
116
117
  var MOCKS_ZK_VERIFIER_ADDRESS = "0x0000000000000000000000000000000000005001";
117
118
  var MOCKS_THRESHOLD_NETWORK_ADDRESS = "0x0000000000000000000000000000000000005002";
118
119
  var MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY = "0x6C8D7F768A6BB4AAFE85E8A2F5A9680355239C7E14646ED62B044E39DE154512";
@@ -748,6 +749,8 @@ var CofheConfigSchema = zod.z.object({
748
749
  }).or(zod.z.null()).default(null),
749
750
  /** Whether to use Web Workers for ZK proof generation (web platform only) */
750
751
  useWorkers: zod.z.boolean().optional().default(true),
752
+ /** How many threads tfhe's rayon pool may use for ZK proof generation (web platform only) */
753
+ tfheThreads: zod.z.union([zod.z.number().int().positive(), zod.z.literal("auto"), zod.z.literal(false)]).optional().default("auto"),
751
754
  /** ACP acp defaults */
752
755
  acp: zod.z.object({
753
756
  defaultRevoker: zod.z.custom().optional(),
@@ -853,6 +856,9 @@ var DEFAULT_KEYS_STORE = {
853
856
  fhe: {},
854
857
  crs: {}
855
858
  };
859
+ function isSecurityZoneRecord(value) {
860
+ return value != null && typeof value === "object";
861
+ }
856
862
  function isStoreWithPersist(store) {
857
863
  return "persist" in store;
858
864
  }
@@ -867,10 +873,10 @@ function createKeysStore(storage) {
867
873
  const stored = keysStore.getState().fhe[chainId]?.[securityZone];
868
874
  return stored;
869
875
  };
870
- const getCrs = (chainId) => {
871
- if (chainId == null)
876
+ const getCrs = (chainId, securityZone = 0) => {
877
+ if (chainId == null || securityZone == null)
872
878
  return void 0;
873
- const stored = keysStore.getState().crs[chainId];
879
+ const stored = keysStore.getState().crs[chainId]?.[securityZone];
874
880
  return stored;
875
881
  };
876
882
  const setFheKey = (chainId, securityZone, key) => {
@@ -882,10 +888,12 @@ function createKeysStore(storage) {
882
888
  })
883
889
  );
884
890
  };
885
- const setCrs = (chainId, crs) => {
891
+ const setCrs = (chainId, securityZone, crs) => {
886
892
  keysStore.setState(
887
893
  immer.produce((state) => {
888
- state.crs[chainId] = crs;
894
+ if (state.crs[chainId] == null)
895
+ state.crs[chainId] = {};
896
+ state.crs[chainId][securityZone] = crs;
889
897
  })
890
898
  );
891
899
  };
@@ -933,7 +941,13 @@ function createStoreWithPersit(storage) {
933
941
  const currentZones = current.fhe[chainId] || {};
934
942
  mergedFhe[chainId] = { ...persistedZones, ...currentZones };
935
943
  }
936
- const mergedCrs = { ...persisted.crs, ...current.crs };
944
+ const mergedCrs = {};
945
+ const allCrsChainIds = /* @__PURE__ */ new Set([...Object.keys(current.crs), ...Object.keys(persisted.crs)]);
946
+ for (const chainId of allCrsChainIds) {
947
+ const persistedZones = isSecurityZoneRecord(persisted.crs[chainId]) ? persisted.crs[chainId] : {};
948
+ const currentZones = isSecurityZoneRecord(current.crs[chainId]) ? current.crs[chainId] : {};
949
+ mergedCrs[chainId] = { ...persistedZones, ...currentZones };
950
+ }
937
951
  return {
938
952
  fhe: mergedFhe,
939
953
  crs: mergedCrs
@@ -995,7 +1009,7 @@ var fetchFhePublicKey = async (coFheUrl, chainId, securityZone, tfhePublicKeyDes
995
1009
  return [pk_data, true];
996
1010
  };
997
1011
  var fetchCrs = async (coFheUrl, chainId, securityZone, compactPkeCrsDeserializer2, keysStorage) => {
998
- const storedKey = keysStorage?.getCrs(chainId);
1012
+ const storedKey = keysStorage?.getCrs(chainId, securityZone);
999
1013
  const [storedKeyValid] = checkKeyValidity(storedKey, compactPkeCrsDeserializer2);
1000
1014
  if (storedKeyValid)
1001
1015
  return [storedKey, false];
@@ -1022,7 +1036,7 @@ var fetchCrs = async (coFheUrl, chainId, securityZone, compactPkeCrsDeserializer
1022
1036
  console.error(`Error serializing CRS ${err}`);
1023
1037
  throw new Error(`Error serializing CRS; ${err}`);
1024
1038
  }
1025
- keysStorage?.setCrs(chainId, crs_data);
1039
+ keysStorage?.setCrs(chainId, securityZone, crs_data);
1026
1040
  return [crs_data, true];
1027
1041
  };
1028
1042
  var fetchKeys = async (config, chainId, securityZone = 0, tfhePublicKeyDeserializer2, compactPkeCrsDeserializer2, keysStorage) => {
@@ -1134,6 +1148,7 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1134
1148
  zkBuilderAndCrsGenerator;
1135
1149
  initTfhe;
1136
1150
  zkProveWorkerFn;
1151
+ beforeMainThreadProve;
1137
1152
  keysStorage;
1138
1153
  // Worker configuration (from config, overrideable)
1139
1154
  useWorker;
@@ -1191,6 +1206,7 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1191
1206
  this.zkBuilderAndCrsGenerator = params.zkBuilderAndCrsGenerator;
1192
1207
  this.initTfhe = params.initTfhe;
1193
1208
  this.zkProveWorkerFn = params.zkProveWorkerFn;
1209
+ this.beforeMainThreadProve = params.beforeMainThreadProve;
1194
1210
  this.keysStorage = params.keysStorage;
1195
1211
  this.useWorker = params.config?.useWorkers ?? true;
1196
1212
  }
@@ -1481,6 +1497,7 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1481
1497
  }
1482
1498
  }
1483
1499
  if (proof == null) {
1500
+ await this.beforeMainThreadProve?.();
1484
1501
  proof = await zkProve(zkBuilder, zkCrs, metadata);
1485
1502
  usedWorker = false;
1486
1503
  }
@@ -1877,11 +1894,40 @@ var SignatureUtils = {
1877
1894
  throw new Error(`Unknown acp type: ${acpType}`);
1878
1895
  }
1879
1896
  };
1897
+ var ADDRESS_BOOK_ABI = viem.parseAbi([
1898
+ "function getTm(uint256 id) view returns (address)",
1899
+ "error TaskManagerNotSet(uint256 id)"
1900
+ ]);
1901
+ var taskManagerAddressCache = /* @__PURE__ */ new Map();
1902
+ var getTaskManagerAddress = async (publicClient, chainId) => {
1903
+ const id = chainId ?? publicClient.chain?.id ?? await publicClient.getChainId();
1904
+ const cached = taskManagerAddressCache.get(id);
1905
+ if (cached != null)
1906
+ return cached;
1907
+ const pending = publicClient.readContract({
1908
+ address: COFHE_ADDRESS_BOOK_ADDRESS,
1909
+ abi: ADDRESS_BOOK_ABI,
1910
+ functionName: "getTm",
1911
+ args: [TASK_MANAGER_ID]
1912
+ }).catch((error) => {
1913
+ taskManagerAddressCache.delete(id);
1914
+ throw CofheError.fromError(error, {
1915
+ code: "TASK_MANAGER_UNRESOLVED" /* TaskManagerUnresolved */,
1916
+ message: `Failed to resolve the Task Manager from the CoFHEAddressBook on chain ${id}`,
1917
+ hint: "Ensure CoFHE is deployed on this chain. On a local hardhat / anvil chain, deploy the CoFHE mocks first.",
1918
+ context: { chainId: id, addressBook: COFHE_ADDRESS_BOOK_ADDRESS, taskManagerId: TASK_MANAGER_ID }
1919
+ });
1920
+ });
1921
+ taskManagerAddressCache.set(id, pending);
1922
+ return pending;
1923
+ };
1924
+
1925
+ // acps/onchain-utils.ts
1880
1926
  var getAclAddress = async (publicClient) => {
1881
1927
  const ACL_IFACE = "function acl() view returns (address)";
1882
1928
  const aclAbi = viem.parseAbi([ACL_IFACE]);
1883
1929
  return await publicClient.readContract({
1884
- address: TASK_MANAGER_ADDRESS,
1930
+ address: await getTaskManagerAddress(publicClient),
1885
1931
  abi: aclAbi,
1886
1932
  functionName: "acl"
1887
1933
  });
@@ -1908,6 +1954,34 @@ var getAclEIP712Domain = async (publicClient) => {
1908
1954
  verifyingContract
1909
1955
  };
1910
1956
  };
1957
+ var toACPTuple = (acp) => ({
1958
+ issuer: acp.issuer,
1959
+ expiration: BigInt(acp.expiration),
1960
+ recipient: acp.recipient,
1961
+ revokerData: BigInt(acp.revokerData),
1962
+ revokerContract: acp.revokerContract,
1963
+ scope: acp.scope,
1964
+ contracts: acp.contracts,
1965
+ handles: acp.handles,
1966
+ sealingKey: acp.sealingKey,
1967
+ issuerSignature: acp.issuerSignature,
1968
+ recipientSignature: acp.recipientSignature
1969
+ });
1970
+ function revertErrorName(err, abi) {
1971
+ const walk = err?.walk;
1972
+ if (typeof walk === "function") {
1973
+ const revertError = walk.call(err, (e) => e?.name === "ContractFunctionRevertedError");
1974
+ if (revertError)
1975
+ return revertError.data?.errorName ?? "";
1976
+ }
1977
+ const customErrorName = extractCustomErrorFromDetails(err, abi);
1978
+ if (customErrorName)
1979
+ return customErrorName;
1980
+ const hhDetailsData = extractReturnData(err);
1981
+ if (hhDetailsData != null)
1982
+ return viem.decodeErrorResult({ abi, data: hhDetailsData }).errorName;
1983
+ return void 0;
1984
+ }
1911
1985
  var checkACPValidityOnChain = async (acp, publicClient) => {
1912
1986
  const aclAddress = await getAclAddress(publicClient);
1913
1987
  try {
@@ -1915,43 +1989,54 @@ var checkACPValidityOnChain = async (acp, publicClient) => {
1915
1989
  address: aclAddress,
1916
1990
  abi: checkACPValidityAbi,
1917
1991
  functionName: "checkPermissionValidity",
1918
- args: [
1919
- {
1920
- issuer: acp.issuer,
1921
- expiration: BigInt(acp.expiration),
1922
- recipient: acp.recipient,
1923
- revokerData: BigInt(acp.revokerData),
1924
- revokerContract: acp.revokerContract,
1925
- scope: acp.scope,
1926
- contracts: acp.contracts,
1927
- handles: acp.handles,
1928
- sealingKey: acp.sealingKey,
1929
- issuerSignature: acp.issuerSignature,
1930
- recipientSignature: acp.recipientSignature
1931
- }
1932
- ]
1992
+ args: [toACPTuple(acp)]
1933
1993
  });
1934
1994
  return true;
1935
1995
  } catch (err) {
1936
- if (err instanceof viem.BaseError) {
1937
- const revertError = err.walk((err2) => err2 instanceof viem.ContractFunctionRevertedError);
1938
- if (revertError instanceof viem.ContractFunctionRevertedError) {
1939
- const errorName = revertError.data?.errorName ?? "";
1940
- throw new Error(errorName);
1941
- }
1942
- }
1943
- const customErrorName = extractCustomErrorFromDetails(err, checkACPValidityAbi);
1944
- if (customErrorName) {
1945
- throw new Error(customErrorName);
1946
- }
1947
- const hhDetailsData = extractReturnData(err);
1948
- if (hhDetailsData != null) {
1949
- const decoded = viem.decodeErrorResult({
1950
- abi: checkACPValidityAbi,
1951
- data: hhDetailsData
1996
+ const errorName = revertErrorName(err, checkACPValidityAbi);
1997
+ if (errorName !== void 0)
1998
+ throw new Error(errorName);
1999
+ throw err;
2000
+ }
2001
+ };
2002
+ var PERMISSION_ERROR_STATUS = {
2003
+ PermissionInvalid_Expired: "expired",
2004
+ PermissionInvalid_Disabled: "revoked",
2005
+ PermissionInvalid_IssuerSignature: "invalid-issuer-signature",
2006
+ PermissionInvalid_RecipientSignature: "invalid-recipient-signature"
2007
+ };
2008
+ var getACPAccessStatusOnChain = async (acp, publicClient, handle) => {
2009
+ const aclAddress = await getAclAddress(publicClient);
2010
+ try {
2011
+ if (handle === void 0) {
2012
+ await publicClient.simulateContract({
2013
+ address: aclAddress,
2014
+ abi: acpAccessAbi,
2015
+ functionName: "checkPermissionValidity",
2016
+ args: [toACPTuple(acp)]
1952
2017
  });
1953
- throw new Error(decoded.errorName);
2018
+ return "valid";
1954
2019
  }
2020
+ const ctHash = BigInt(handle);
2021
+ const allowed = await publicClient.readContract({
2022
+ address: aclAddress,
2023
+ abi: acpAccessAbi,
2024
+ functionName: "isAllowedWithPermission",
2025
+ args: [toACPTuple(acp), ctHash]
2026
+ });
2027
+ if (allowed)
2028
+ return "allowed";
2029
+ const issuerAllowed = await publicClient.readContract({
2030
+ address: aclAddress,
2031
+ abi: acpAccessAbi,
2032
+ functionName: "isAllowed",
2033
+ args: [ctHash, acp.issuer]
2034
+ });
2035
+ return issuerAllowed ? "out-of-scope" : "issuer-not-allowed";
2036
+ } catch (err) {
2037
+ const status = PERMISSION_ERROR_STATUS[revertErrorName(err, acpAccessAbi) ?? ""];
2038
+ if (status)
2039
+ return status;
1955
2040
  throw err;
1956
2041
  }
1957
2042
  };
@@ -1973,7 +2058,8 @@ function extractCustomErrorFromDetails(err, abi) {
1973
2058
  function extractReturnData(err) {
1974
2059
  const anyErr = err;
1975
2060
  const s = anyErr?.details ?? anyErr?.cause?.details ?? anyErr?.shortMessage ?? anyErr?.message ?? String(err);
1976
- return s.match(/return data:\s*(0x[a-fA-F0-9]+)/)?.[1];
2061
+ const match = s.match(/return data:\s*(0x[a-fA-F0-9]+)/) ?? s.match(/custom error (0x[a-fA-F0-9]{8,})/);
2062
+ return match?.[1];
1977
2063
  }
1978
2064
  var checkACPValidityAbi = [
1979
2065
  {
@@ -2073,6 +2159,58 @@ var checkACPValidityAbi = [
2073
2159
  inputs: []
2074
2160
  }
2075
2161
  ];
2162
+ var acpAccessAbi = [
2163
+ ...checkACPValidityAbi,
2164
+ {
2165
+ type: "function",
2166
+ name: "isAllowedWithPermission",
2167
+ inputs: [checkACPValidityAbi[0].inputs[0], { name: "handle", type: "uint256", internalType: "uint256" }],
2168
+ outputs: [{ name: "", type: "bool", internalType: "bool" }],
2169
+ stateMutability: "view"
2170
+ },
2171
+ {
2172
+ type: "function",
2173
+ name: "isAllowed",
2174
+ inputs: [
2175
+ { name: "handle", type: "uint256", internalType: "uint256" },
2176
+ { name: "account", type: "address", internalType: "address" }
2177
+ ],
2178
+ outputs: [{ name: "", type: "bool", internalType: "bool" }],
2179
+ stateMutability: "view"
2180
+ }
2181
+ ];
2182
+ var ACL_SERVED_ADDRESSES_ABI = viem.parseAbi([
2183
+ "function acl() view returns (address)",
2184
+ "function defaultRevokerContract() view returns (address)",
2185
+ "function shareRegistry() view returns (address)"
2186
+ ]);
2187
+ var aclServedAddressesCache = /* @__PURE__ */ new Map();
2188
+ var clearAclServedAddresses = () => aclServedAddressesCache.clear();
2189
+ var getAclServedAddresses = async (publicClient, chainId) => {
2190
+ const cached = aclServedAddressesCache.get(chainId);
2191
+ if (cached != null)
2192
+ return cached;
2193
+ let aclAddress;
2194
+ try {
2195
+ aclAddress = await publicClient.readContract({
2196
+ address: await getTaskManagerAddress(publicClient, chainId),
2197
+ abi: ACL_SERVED_ADDRESSES_ABI,
2198
+ functionName: "acl"
2199
+ });
2200
+ } catch {
2201
+ return {};
2202
+ }
2203
+ const [defaultRevoker, shareRegistry] = await Promise.all([
2204
+ publicClient.readContract({ address: aclAddress, abi: ACL_SERVED_ADDRESSES_ABI, functionName: "defaultRevokerContract" }).catch(() => void 0),
2205
+ publicClient.readContract({ address: aclAddress, abi: ACL_SERVED_ADDRESSES_ABI, functionName: "shareRegistry" }).catch(() => void 0)
2206
+ ]);
2207
+ const resolved = {
2208
+ defaultRevoker: defaultRevoker != null && defaultRevoker !== viem.zeroAddress ? defaultRevoker : void 0,
2209
+ shareRegistry: shareRegistry != null && shareRegistry !== viem.zeroAddress ? shareRegistry : void 0
2210
+ };
2211
+ aclServedAddressesCache.set(chainId, resolved);
2212
+ return resolved;
2213
+ };
2076
2214
 
2077
2215
  // acps/acp.ts
2078
2216
  var ACPUtils = {
@@ -2386,8 +2524,62 @@ var ACPUtils = {
2386
2524
  checkValidityOnChain: async (acp, publicClient) => {
2387
2525
  const publicAcp = ACPUtils.getPublic(acp);
2388
2526
  return checkACPValidityOnChain(publicAcp, publicClient);
2527
+ },
2528
+ /**
2529
+ * The acp on-chain status as a value instead of a revert: 'valid' or why not, and given a
2530
+ * handle, whether the acp may read it (see `ACPAccessStatus`).
2531
+ */
2532
+ checkAccessOnChain: async (acp, publicClient, handle) => {
2533
+ return getACPAccessStatusOnChain(ACPUtils.getPublic(acp), publicClient, handle);
2389
2534
  }
2390
2535
  };
2536
+ var ACP_REVOKER_ABI = viem.parseAbi([
2537
+ "function revokeSingle(uint256 id)",
2538
+ "function revokeAllExisting()",
2539
+ "function disabled(address issuer, uint256 id) view returns (bool)"
2540
+ ]);
2541
+ var ACP_SHARE_REGISTRY_ABI = viem.parseAbi([
2542
+ "struct ACP { address issuer; uint64 expiration; address recipient; uint256 revokerData; address revokerContract; uint8 scope; address[] contracts; bytes32[] handles; bytes32 sealingKey; bytes issuerSignature; bytes recipientSignature; }",
2543
+ "function share(ACP calldata acp) external returns (bytes32)",
2544
+ "function removeShare(bytes32 shareId) external",
2545
+ "function sharesFor(address recipient) external view returns (ACP[] memory)",
2546
+ "function getShare(bytes32 shareId) external view returns (ACP memory)",
2547
+ "function isShareValid(bytes32 shareId) external view returns (bool)"
2548
+ ]);
2549
+ var ACP_SHARE_TUPLE_ABI = [
2550
+ {
2551
+ type: "tuple",
2552
+ components: [
2553
+ { name: "issuer", type: "address" },
2554
+ { name: "expiration", type: "uint64" },
2555
+ { name: "recipient", type: "address" },
2556
+ { name: "revokerData", type: "uint256" },
2557
+ { name: "revokerContract", type: "address" },
2558
+ { name: "scope", type: "uint8" },
2559
+ { name: "contracts", type: "address[]" },
2560
+ { name: "handles", type: "bytes32[]" },
2561
+ { name: "sealingKey", type: "bytes32" },
2562
+ { name: "issuerSignature", type: "bytes" },
2563
+ { name: "recipientSignature", type: "bytes" }
2564
+ ]
2565
+ }
2566
+ ];
2567
+ var ZERO_BYTES32 = `0x${"0".repeat(64)}`;
2568
+ var toChainShare = (acp) => {
2569
+ const pub = ACPUtils.getPublic(acp, true);
2570
+ return {
2571
+ ...pub,
2572
+ expiration: BigInt(pub.expiration),
2573
+ revokerData: BigInt(pub.revokerData),
2574
+ sealingKey: ZERO_BYTES32,
2575
+ recipientSignature: "0x"
2576
+ };
2577
+ };
2578
+ var computeShareId = (acp) => {
2579
+ const p = toChainShare(acp);
2580
+ return viem.keccak256(viem.encodeAbiParameters(ACP_SHARE_TUPLE_ABI, [p]));
2581
+ };
2582
+ var shareIdOfChainShare = (share) => viem.keccak256(viem.encodeAbiParameters(ACP_SHARE_TUPLE_ABI, [share]));
2391
2583
  var ACP_STORE_DEFAULTS = {
2392
2584
  acps: {},
2393
2585
  activeACPHash: {}
@@ -2513,11 +2705,6 @@ var acpStore = {
2513
2705
  removeActiveACPHash,
2514
2706
  resetStore
2515
2707
  };
2516
- var ACP_VALIDATOR_ABI = viem.parseAbi([
2517
- "function revokeSingle(uint256 id)",
2518
- "function revokeAllExisting()",
2519
- "function disabled(address issuer, uint256 id) view returns (bool)"
2520
- ]);
2521
2708
  var storeACP = async (acp, publicClient, walletClient) => {
2522
2709
  const chainId = await publicClient.getChainId();
2523
2710
  const account = walletClient.account.address;
@@ -2544,8 +2731,8 @@ var createSelf = async (options, publicClient, walletClient) => {
2544
2731
  var createSharing = async (options, publicClient, walletClient) => {
2545
2732
  return createACPWithSign(options, publicClient, walletClient, ACPUtils.createSharingAndSign, false);
2546
2733
  };
2547
- var importShared = async (options, publicClient, walletClient) => {
2548
- return createACPWithSign(options, publicClient, walletClient, ACPUtils.importSharedAndSign);
2734
+ var importShared = async (options, publicClient, walletClient, { activate = true } = {}) => {
2735
+ return createACPWithSign(options, publicClient, walletClient, ACPUtils.importSharedAndSign, activate);
2549
2736
  };
2550
2737
  var getHash = (acp) => {
2551
2738
  return ACPUtils.getHash(acp);
@@ -2607,38 +2794,6 @@ var applyACPDefaults = (options, acpConfig, chainId) => {
2607
2794
  }
2608
2795
  return result;
2609
2796
  };
2610
- var ACL_SERVED_ADDRESSES_ABI = viem.parseAbi([
2611
- "function acl() view returns (address)",
2612
- "function defaultRevokerContract() view returns (address)",
2613
- "function shareRegistry() view returns (address)"
2614
- ]);
2615
- var aclServedAddressesCache = /* @__PURE__ */ new Map();
2616
- var clearAclServedAddresses = () => aclServedAddressesCache.clear();
2617
- var getAclServedAddresses = async (publicClient, chainId) => {
2618
- const cached = aclServedAddressesCache.get(chainId);
2619
- if (cached != null)
2620
- return cached;
2621
- let aclAddress;
2622
- try {
2623
- aclAddress = await publicClient.readContract({
2624
- address: TASK_MANAGER_ADDRESS,
2625
- abi: ACL_SERVED_ADDRESSES_ABI,
2626
- functionName: "acl"
2627
- });
2628
- } catch {
2629
- return {};
2630
- }
2631
- const [defaultRevoker, shareRegistry] = await Promise.all([
2632
- publicClient.readContract({ address: aclAddress, abi: ACL_SERVED_ADDRESSES_ABI, functionName: "defaultRevokerContract" }).catch(() => void 0),
2633
- publicClient.readContract({ address: aclAddress, abi: ACL_SERVED_ADDRESSES_ABI, functionName: "shareRegistry" }).catch(() => void 0)
2634
- ]);
2635
- const resolved = {
2636
- defaultRevoker: defaultRevoker != null && defaultRevoker !== viem.zeroAddress ? defaultRevoker : void 0,
2637
- shareRegistry: shareRegistry != null && shareRegistry !== viem.zeroAddress ? shareRegistry : void 0
2638
- };
2639
- aclServedAddressesCache.set(chainId, resolved);
2640
- return resolved;
2641
- };
2642
2797
  var applyACPDefaultsFromChain = async (options, acpConfig, publicClient, chainId) => {
2643
2798
  const hasExplicitRevoker = acpConfig?.defaultRevoker?.[chainId] != null || options.revokerData != null || options.revokerContract != null;
2644
2799
  if (hasExplicitRevoker)
@@ -2658,7 +2813,7 @@ var revokeACP = async (acp, walletClient) => {
2658
2813
  }
2659
2814
  return walletClient.writeContract({
2660
2815
  address: acp.revokerContract,
2661
- abi: ACP_VALIDATOR_ABI,
2816
+ abi: ACP_REVOKER_ABI,
2662
2817
  functionName: "revokeSingle",
2663
2818
  args: [BigInt(acp.revokerData)],
2664
2819
  account: walletClient.account,
@@ -2679,64 +2834,31 @@ var revokeAllACPs = async (walletClient, publicClient, revokerContract) => {
2679
2834
  }
2680
2835
  return walletClient.writeContract({
2681
2836
  address: revoker,
2682
- abi: ACP_VALIDATOR_ABI,
2837
+ abi: ACP_REVOKER_ABI,
2683
2838
  functionName: "revokeAllExisting",
2684
2839
  args: [],
2685
2840
  account: walletClient.account,
2686
2841
  chain: walletClient.chain
2687
2842
  });
2688
2843
  };
2844
+ var checkAccess = async (acp, publicClient, handle) => {
2845
+ if (acp.type === "sharing" && handle === void 0) {
2846
+ if (ACPUtils.isExpired(acp))
2847
+ return "expired";
2848
+ return await isACPRevoked(acp, publicClient) ? "revoked" : "valid";
2849
+ }
2850
+ return ACPUtils.checkAccessOnChain(acp, publicClient, handle);
2851
+ };
2689
2852
  var isACPRevoked = async (acp, publicClient) => {
2690
2853
  if (acp.revokerContract === viem.zeroAddress || acp.revokerData === 0)
2691
2854
  return false;
2692
2855
  return publicClient.readContract({
2693
2856
  address: acp.revokerContract,
2694
- abi: ACP_VALIDATOR_ABI,
2857
+ abi: ACP_REVOKER_ABI,
2695
2858
  functionName: "disabled",
2696
2859
  args: [acp.issuer, BigInt(acp.revokerData)]
2697
2860
  });
2698
2861
  };
2699
- var ACP_SHARE_REGISTRY_ABI = viem.parseAbi([
2700
- "struct ACP { address issuer; uint64 expiration; address recipient; uint256 revokerData; address revokerContract; uint8 scope; address[] contracts; bytes32[] handles; bytes32 sealingKey; bytes issuerSignature; bytes recipientSignature; }",
2701
- "function share(ACP calldata acp) external returns (bytes32)",
2702
- "function removeShare(bytes32 shareId) external",
2703
- "function sharesFor(address recipient) external view returns (ACP[] memory)",
2704
- "function getShare(bytes32 shareId) external view returns (ACP memory)",
2705
- "function isShareValid(bytes32 shareId) external view returns (bool)"
2706
- ]);
2707
- var ACP_TUPLE = [
2708
- {
2709
- type: "tuple",
2710
- components: [
2711
- { name: "issuer", type: "address" },
2712
- { name: "expiration", type: "uint64" },
2713
- { name: "recipient", type: "address" },
2714
- { name: "revokerData", type: "uint256" },
2715
- { name: "revokerContract", type: "address" },
2716
- { name: "scope", type: "uint8" },
2717
- { name: "contracts", type: "address[]" },
2718
- { name: "handles", type: "bytes32[]" },
2719
- { name: "sealingKey", type: "bytes32" },
2720
- { name: "issuerSignature", type: "bytes" },
2721
- { name: "recipientSignature", type: "bytes" }
2722
- ]
2723
- }
2724
- ];
2725
- var ZERO_BYTES32 = `0x${"0".repeat(64)}`;
2726
- var toChainShare = (acp) => {
2727
- const pub = ACPUtils.getPublic(acp, true);
2728
- return {
2729
- ...pub,
2730
- expiration: BigInt(pub.expiration),
2731
- revokerData: BigInt(pub.revokerData),
2732
- sealingKey: ZERO_BYTES32,
2733
- recipientSignature: "0x"
2734
- };
2735
- };
2736
- var computeShareId = (acp) => {
2737
- const p = toChainShare(acp);
2738
- return viem.keccak256(viem.encodeAbiParameters(ACP_TUPLE, [p]));
2739
- };
2740
2862
  var shareOnChain = async (acp, walletClient, registry) => {
2741
2863
  if (acp.type !== "sharing") {
2742
2864
  throw new Error(`Cannot share a '${acp.type}' ACP on-chain \u2014 only 'sharing' ACPs are shareable.`);
@@ -2767,7 +2889,7 @@ var getIncomingShares = async (publicClient, registry, recipient) => {
2767
2889
  args: [recipient]
2768
2890
  });
2769
2891
  return raw.map((s) => ({
2770
- shareId: viem.keccak256(viem.encodeAbiParameters(ACP_TUPLE, [s])),
2892
+ shareId: shareIdOfChainShare(s),
2771
2893
  issuer: s.issuer,
2772
2894
  expiration: Number(s.expiration),
2773
2895
  recipient: s.recipient,
@@ -2779,9 +2901,9 @@ var getIncomingShares = async (publicClient, registry, recipient) => {
2779
2901
  issuerSignature: s.issuerSignature
2780
2902
  }));
2781
2903
  };
2782
- var importFromChain = async (share, publicClient, walletClient) => {
2904
+ var importFromChain = async (share, publicClient, walletClient, importOptions = {}) => {
2783
2905
  const { shareId: _shareId, ...options } = share;
2784
- return importShared({ ...options, type: "sharing" }, publicClient, walletClient);
2906
+ return importShared({ ...options, type: "sharing" }, publicClient, walletClient, importOptions);
2785
2907
  };
2786
2908
  var removeShareOnChain = async (shareId, walletClient, registry) => {
2787
2909
  if (walletClient.account == null)
@@ -2819,6 +2941,7 @@ var acps = {
2819
2941
  revokeACP,
2820
2942
  revokeAllACPs,
2821
2943
  isACPRevoked,
2944
+ checkAccess,
2822
2945
  shareOnChain,
2823
2946
  getIncomingShares,
2824
2947
  importFromChain,
@@ -4531,7 +4654,7 @@ var buildDecryptResultHash = (ctHash, cleartext, chainId) => {
4531
4654
  async function verifyDecryptResult(handle, cleartext, signature, publicClient) {
4532
4655
  const chainId = publicClient.chain?.id ?? await publicClient.getChainId();
4533
4656
  const expectedSigner = await publicClient.readContract({
4534
- address: TASK_MANAGER_ADDRESS,
4657
+ address: await getTaskManagerAddress(publicClient, chainId),
4535
4658
  abi: decryptResultSignerAbi,
4536
4659
  functionName: "decryptResultSigner",
4537
4660
  args: []
@@ -4651,6 +4774,7 @@ function createCofheClientBase(opts) {
4651
4774
  zkBuilderAndCrsGenerator: opts.zkBuilderAndCrsGenerator,
4652
4775
  initTfhe: opts.initTfhe,
4653
4776
  zkProveWorkerFn: opts.zkProveWorkerFn,
4777
+ beforeMainThreadProve: opts.beforeMainThreadProve,
4654
4778
  keysStorage,
4655
4779
  requireConnected: _requireConnected
4656
4780
  });
@@ -4727,10 +4851,11 @@ function createCofheClientBase(opts) {
4727
4851
  walletClient
4728
4852
  );
4729
4853
  },
4730
- importShared: async (options, clients) => {
4854
+ importShared: async (options, importOptions = {}) => {
4731
4855
  _requireConnected();
4732
- const { publicClient, walletClient } = clients ?? connectStore.getState();
4733
- return acps.importShared(options, publicClient, walletClient);
4856
+ const { activate, ...clients } = importOptions;
4857
+ const { publicClient, walletClient } = clients.publicClient ? clients : connectStore.getState();
4858
+ return acps.importShared(options, publicClient, walletClient, { activate });
4734
4859
  },
4735
4860
  // Get or create methods (require connection)
4736
4861
  getOrCreateSelfACP: async (chainId, account, options) => {
@@ -4773,6 +4898,11 @@ function createCofheClientBase(opts) {
4773
4898
  const { publicClient } = connectStore.getState();
4774
4899
  return acps.isACPRevoked(acp, publicClient);
4775
4900
  },
4901
+ checkAccess: async (acp, handle) => {
4902
+ _requireConnected();
4903
+ const { publicClient } = connectStore.getState();
4904
+ return acps.checkAccess(acp, publicClient, handle);
4905
+ },
4776
4906
  // On-chain sharing (require connection + config.acp.sharingRegistry)
4777
4907
  shareOnChain: async (acp) => {
4778
4908
  _requireConnected();
@@ -4789,10 +4919,10 @@ function createCofheClientBase(opts) {
4789
4919
  const sharingRegistry = await _resolveSharingRegistry(publicClient, chainId);
4790
4920
  return acps.getIncomingShares(publicClient, sharingRegistry, account);
4791
4921
  },
4792
- importFromChain: async (share) => {
4922
+ importFromChain: async (share, options) => {
4793
4923
  _requireConnected();
4794
4924
  const { publicClient, walletClient } = connectStore.getState();
4795
- return acps.importFromChain(share, publicClient, walletClient);
4925
+ return acps.importFromChain(share, publicClient, walletClient, options);
4796
4926
  },
4797
4927
  dismissShare: async (shareId) => {
4798
4928
  _requireConnected();
@@ -5004,7 +5134,7 @@ var ZkProveWorkerManager = class {
5004
5134
  /**
5005
5135
  * Submit a proof generation request to the worker
5006
5136
  */
5007
- async submitProof(fheKeyHex, crsHex, items, metadata) {
5137
+ async submitProof(fheKeyHex, crsHex, items, metadata, tfheThreads) {
5008
5138
  await this.initializeWorker();
5009
5139
  const id = `zkprove-${Date.now()}-${this.requestCounter++}`;
5010
5140
  return new Promise((resolve, reject) => {
@@ -5019,7 +5149,8 @@ var ZkProveWorkerManager = class {
5019
5149
  fheKeyHex,
5020
5150
  crsHex,
5021
5151
  items,
5022
- metadata: Array.from(metadata)
5152
+ metadata: Array.from(metadata),
5153
+ tfheThreads
5023
5154
  };
5024
5155
  this.worker.postMessage(message);
5025
5156
  });
@@ -5064,17 +5195,91 @@ function areWorkersAvailable() {
5064
5195
  return typeof Worker !== "undefined";
5065
5196
  }
5066
5197
 
5198
+ // web/tfheThreadPool.ts
5199
+ var MAX_AUTO_THREADS = 8;
5200
+ function resolveThreadCount(setting = "auto") {
5201
+ if (setting === false)
5202
+ return 1;
5203
+ if (typeof setting === "number") {
5204
+ return Number.isFinite(setting) && setting >= 1 ? Math.floor(setting) : 1;
5205
+ }
5206
+ const cores = globalThis.navigator?.hardwareConcurrency ?? 1;
5207
+ if (!Number.isFinite(cores) || cores < 1)
5208
+ return 1;
5209
+ return Math.min(Math.floor(cores), MAX_AUTO_THREADS);
5210
+ }
5211
+ function isCrossOriginIsolated() {
5212
+ return globalThis.crossOriginIsolated === true;
5213
+ }
5214
+ async function initTfheThreadPool(mod, setting = "auto") {
5215
+ if (setting === false) {
5216
+ return { enabled: false, threads: 1, reason: "disabled via config.tfheThreads" };
5217
+ }
5218
+ if (typeof mod.initThreadPool !== "function") {
5219
+ return { enabled: false, threads: 1, reason: "tfhe build has no initThreadPool (single-threaded wasm)" };
5220
+ }
5221
+ if (typeof Worker === "undefined") {
5222
+ return { enabled: false, threads: 1, reason: "Worker is unavailable" };
5223
+ }
5224
+ if (!isCrossOriginIsolated()) {
5225
+ return {
5226
+ enabled: false,
5227
+ threads: 1,
5228
+ reason: "not cross-origin isolated \u2014 serve the page with Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp (or credentialless) to enable multi-threaded proving"
5229
+ };
5230
+ }
5231
+ const threads = resolveThreadCount(setting);
5232
+ if (threads <= 1) {
5233
+ return { enabled: false, threads: 1, reason: "resolved to a single thread" };
5234
+ }
5235
+ try {
5236
+ await mod.initThreadPool(threads);
5237
+ return { enabled: true, threads };
5238
+ } catch (error) {
5239
+ return {
5240
+ enabled: false,
5241
+ threads: 1,
5242
+ reason: `initThreadPool failed: ${error instanceof Error ? error.message : String(error)}`
5243
+ };
5244
+ }
5245
+ }
5246
+
5067
5247
  // web/index.ts
5068
5248
  var tfheModule = null;
5069
5249
  var tfheInitialized = false;
5070
- async function initTfhe() {
5250
+ var tfheInitPromise = null;
5251
+ var threadPoolPromise = null;
5252
+ var threadPoolResult = null;
5253
+ function getTfheThreadPoolStatus() {
5254
+ return threadPoolResult;
5255
+ }
5256
+ var initTfhe = async () => {
5071
5257
  if (tfheInitialized)
5072
5258
  return false;
5073
- tfheModule = await import('tfhe');
5074
- await tfheModule.default();
5075
- await tfheModule.init_panic_hook();
5076
- tfheInitialized = true;
5259
+ if (tfheInitPromise) {
5260
+ await tfheInitPromise;
5261
+ return false;
5262
+ }
5263
+ tfheInitPromise = (async () => {
5264
+ const mod = await import('tfhe');
5265
+ await mod.default();
5266
+ await mod.init_panic_hook();
5267
+ tfheModule = mod;
5268
+ tfheInitialized = true;
5269
+ })();
5270
+ try {
5271
+ await tfheInitPromise;
5272
+ } catch (error) {
5273
+ tfheInitPromise = null;
5274
+ throw error;
5275
+ }
5077
5276
  return true;
5277
+ };
5278
+ function createStartMainThreadPool(tfheThreads) {
5279
+ return async () => {
5280
+ threadPoolPromise ??= initTfheThreadPool(requireTfhe(), tfheThreads);
5281
+ threadPoolResult = await threadPoolPromise;
5282
+ };
5078
5283
  }
5079
5284
  function requireTfhe() {
5080
5285
  if (!tfheModule) {
@@ -5110,13 +5315,15 @@ var zkBuilderAndCrsGenerator = (fhe, crs) => {
5110
5315
  const zkCrs = _deserializeCompactPkeCrs(crs);
5111
5316
  return { zkBuilder, zkCrs };
5112
5317
  };
5113
- async function zkProveWithWorker2(fheKeyHex, crsHex, items, metadata) {
5114
- const serializedItems = items.map((item) => ({
5115
- utype: fheTypeToString(item.utype),
5116
- data: typeof item.data === "bigint" ? item.data.toString() : item.data
5117
- }));
5118
- const workerManager2 = getWorkerManager();
5119
- return await workerManager2.submitProof(fheKeyHex, crsHex, serializedItems, metadata);
5318
+ function createZkProveWithWorker(tfheThreads) {
5319
+ return async function zkProveWithWorker2(fheKeyHex, crsHex, items, metadata) {
5320
+ const serializedItems = items.map((item) => ({
5321
+ utype: fheTypeToString(item.utype),
5322
+ data: typeof item.data === "bigint" ? item.data.toString() : item.data
5323
+ }));
5324
+ const workerManager2 = getWorkerManager();
5325
+ return await workerManager2.submitProof(fheKeyHex, crsHex, serializedItems, metadata, tfheThreads);
5326
+ };
5120
5327
  }
5121
5328
  function createCofheConfig(config) {
5122
5329
  return createCofheConfigBase({
@@ -5132,9 +5339,10 @@ function createCofheClient(config) {
5132
5339
  tfhePublicKeyDeserializer,
5133
5340
  compactPkeCrsDeserializer,
5134
5341
  initTfhe,
5342
+ beforeMainThreadProve: createStartMainThreadPool(config.tfheThreads),
5135
5343
  // Always provide the worker function if available - config.useWorkers controls usage
5136
5344
  // areWorkersAvailable will return true if the Worker API is available and false in Node.js
5137
- zkProveWorkerFn: areWorkersAvailable() ? zkProveWithWorker2 : void 0
5345
+ zkProveWorkerFn: areWorkersAvailable() ? createZkProveWithWorker(config.tfheThreads) : void 0
5138
5346
  });
5139
5347
  }
5140
5348
  function createCofheClientWithCustomWorker(config, customZkProveWorkerFn) {
@@ -5144,6 +5352,7 @@ function createCofheClientWithCustomWorker(config, customZkProveWorkerFn) {
5144
5352
  tfhePublicKeyDeserializer,
5145
5353
  compactPkeCrsDeserializer,
5146
5354
  initTfhe,
5355
+ beforeMainThreadProve: createStartMainThreadPool(config.tfheThreads),
5147
5356
  zkProveWorkerFn: customZkProveWorkerFn
5148
5357
  });
5149
5358
  }
@@ -5153,5 +5362,6 @@ exports.createCofheClient = createCofheClient;
5153
5362
  exports.createCofheClientWithCustomWorker = createCofheClientWithCustomWorker;
5154
5363
  exports.createCofheConfig = createCofheConfig;
5155
5364
  exports.createSsrStorage = createSsrStorage;
5365
+ exports.getTfheThreadPoolStatus = getTfheThreadPoolStatus;
5156
5366
  exports.hasDOM = hasDOM;
5157
5367
  exports.terminateWorker = terminateWorker;