@cofhe/sdk 1.0.0-alpha.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/acps/onchain-utils.ts +15 -10
  3. package/acps/sealing.ts +22 -2
  4. package/acps/test/aclServedAddresses.test.ts +65 -0
  5. package/acps/test/sealing.test.ts +51 -0
  6. package/core/encrypt/encryptInputsBuilder.ts +31 -13
  7. package/core/encrypt/zkPackProveVerify.ts +16 -4
  8. package/core/error.ts +1 -0
  9. package/core/test/encryptInputsBuilder.test.ts +56 -4
  10. package/core/test/zkPoKMetadata.test.ts +27 -0
  11. package/dist/acps.cjs +122 -99
  12. package/dist/acps.d.cts +2 -2
  13. package/dist/acps.d.ts +2 -2
  14. package/dist/acps.js +2 -2
  15. package/dist/{chunk-6ZW76ZKB.js → chunk-3SD2UCRE.js} +1 -1
  16. package/dist/{chunk-OL3DZN7A.js → chunk-GKEJHZ52.js} +35 -19
  17. package/dist/{chunk-XQ32JG3T.js → chunk-OC5TGQGG.js} +14 -13
  18. package/dist/{chunk-BQWHPIYU.js → chunk-WAA2U7CT.js} +29 -6
  19. package/dist/{clientTypes-C0A9ji5O.d.cts → clientTypes-C2b_qub5.d.cts} +6 -3
  20. package/dist/{clientTypes-CcU5WvdV.d.ts → clientTypes-DEKYh0cw.d.ts} +6 -3
  21. package/dist/core.cjs +220 -180
  22. package/dist/core.d.cts +4 -3
  23. package/dist/core.d.ts +4 -3
  24. package/dist/core.js +4 -4
  25. package/dist/node.cjs +153 -114
  26. package/dist/node.d.cts +2 -2
  27. package/dist/node.d.ts +2 -2
  28. package/dist/node.js +4 -4
  29. package/dist/{onchain-utils-D9Z33IP7.d.cts → onchain-utils-CgOslubH.d.cts} +3 -3
  30. package/dist/{onchain-utils-D9Z33IP7.d.ts → onchain-utils-CgOslubH.d.ts} +3 -3
  31. package/dist/web.cjs +153 -114
  32. package/dist/web.d.cts +2 -2
  33. package/dist/web.d.ts +2 -2
  34. package/dist/web.js +4 -4
  35. package/dist/zkProve.worker.js +2 -2
  36. package/package.json +1 -1
package/dist/web.cjs CHANGED
@@ -43,6 +43,100 @@ function toBigInt(value) {
43
43
  }
44
44
  }
45
45
 
46
+ // core/error.ts
47
+ var CofheError = class _CofheError extends Error {
48
+ code;
49
+ cause;
50
+ hint;
51
+ context;
52
+ apiErrorCode;
53
+ constructor({ code, message, cause, hint, context, apiErrorCode }) {
54
+ const fullMessage = cause ? `${message} | Caused by: ${cause.message}` : message;
55
+ super(fullMessage);
56
+ this.name = "CofheError";
57
+ this.code = code;
58
+ this.cause = cause;
59
+ this.hint = hint;
60
+ this.context = context;
61
+ this.apiErrorCode = apiErrorCode;
62
+ if (Error.captureStackTrace) {
63
+ Error.captureStackTrace(this, _CofheError);
64
+ }
65
+ }
66
+ /**
67
+ * Creates a CofheError from an unknown error
68
+ * If the error is a CofheError, it is returned unchanged, else a new CofheError is created
69
+ * If a wrapperError is provided, it is used to create the new CofheError, else a default is used
70
+ */
71
+ static fromError(error, wrapperError) {
72
+ if (isCofheError(error))
73
+ return error;
74
+ const cause = error instanceof Error ? error : new Error(`${error}`);
75
+ return new _CofheError({
76
+ code: wrapperError?.code ?? "INTERNAL_ERROR" /* InternalError */,
77
+ message: wrapperError?.message ?? "An internal error occurred",
78
+ hint: wrapperError?.hint,
79
+ context: wrapperError?.context,
80
+ apiErrorCode: wrapperError?.apiErrorCode,
81
+ cause
82
+ });
83
+ }
84
+ /**
85
+ * Serializes the error to JSON string with proper handling of Error objects
86
+ */
87
+ serialize() {
88
+ return bigintSafeJsonStringify({
89
+ name: this.name,
90
+ code: this.code,
91
+ message: this.message,
92
+ hint: this.hint,
93
+ context: this.context,
94
+ apiErrorCode: this.apiErrorCode,
95
+ cause: this.cause ? {
96
+ name: this.cause.name,
97
+ message: this.cause.message,
98
+ stack: this.cause.stack
99
+ } : void 0,
100
+ stack: this.stack
101
+ });
102
+ }
103
+ /**
104
+ * Returns a human-readable string representation of the error
105
+ */
106
+ toString() {
107
+ const codeSuffix = this.apiErrorCode ? ` (api: ${this.apiErrorCode})` : "";
108
+ const parts = [`${this.name} [${this.code}]${codeSuffix}: ${this.message}`];
109
+ if (this.hint) {
110
+ parts.push(`Hint: ${this.hint}`);
111
+ }
112
+ if (this.context && Object.keys(this.context).length > 0) {
113
+ parts.push(`Context: ${bigintSafeJsonStringify(this.context)}`);
114
+ }
115
+ if (this.stack) {
116
+ parts.push(`
117
+ Stack trace:`);
118
+ parts.push(this.stack);
119
+ }
120
+ if (this.cause) {
121
+ parts.push(`
122
+ Caused by: ${this.cause.name}: ${this.cause.message}`);
123
+ if (this.cause.stack) {
124
+ parts.push(this.cause.stack);
125
+ }
126
+ }
127
+ return parts.join("\n");
128
+ }
129
+ };
130
+ var bigintSafeJsonStringify = (value) => {
131
+ return JSON.stringify(value, (key, value2) => {
132
+ if (typeof value2 === "bigint") {
133
+ return `${value2}n`;
134
+ }
135
+ return value2;
136
+ });
137
+ };
138
+ var isCofheError = (error) => error instanceof CofheError;
139
+
46
140
  // acps/sealing.ts
47
141
  var KEY_HEX_LENGTH = 64;
48
142
  var GenerateSealingKey = () => {
@@ -57,9 +151,25 @@ var unsealWithPrivateKey = (privateKey, parsedData) => {
57
151
  const nonce = parsedData.nonce instanceof Uint8Array ? parsedData.nonce : new Uint8Array(parsedData.nonce);
58
152
  const ephemPublicKey = parsedData.public_key instanceof Uint8Array ? parsedData.public_key : new Uint8Array(parsedData.public_key);
59
153
  const dataToDecrypt = parsedData.data instanceof Uint8Array ? parsedData.data : new Uint8Array(parsedData.data);
60
- const decryptedMessage = nacl__default.default.box.open(dataToDecrypt, nonce, ephemPublicKey, fromHexString(privateKey));
154
+ let decryptedMessage;
155
+ let cause;
156
+ try {
157
+ decryptedMessage = nacl__default.default.box.open(dataToDecrypt, nonce, ephemPublicKey, fromHexString(privateKey));
158
+ } catch (e) {
159
+ decryptedMessage = null;
160
+ cause = e instanceof Error ? e : void 0;
161
+ }
61
162
  if (!decryptedMessage) {
62
- throw new Error("Failed to decrypt message");
163
+ throw new CofheError({
164
+ code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
165
+ message: "Failed to unseal decrypt response",
166
+ cause,
167
+ context: {
168
+ dataLength: dataToDecrypt.length,
169
+ nonceLength: nonce.length,
170
+ publicKeyLength: ephemPublicKey.length
171
+ }
172
+ });
63
173
  }
64
174
  return toBigInt(decryptedMessage);
65
175
  };
@@ -377,100 +487,6 @@ var TFHE_RS_ZK_MAX_BITS = 2048;
377
487
  var TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT = BigInt(1 << 30);
378
488
  var TFHE_RS_KEY_VERSION = 2;
379
489
 
380
- // core/error.ts
381
- var CofheError = class _CofheError extends Error {
382
- code;
383
- cause;
384
- hint;
385
- context;
386
- apiErrorCode;
387
- constructor({ code, message, cause, hint, context, apiErrorCode }) {
388
- const fullMessage = cause ? `${message} | Caused by: ${cause.message}` : message;
389
- super(fullMessage);
390
- this.name = "CofheError";
391
- this.code = code;
392
- this.cause = cause;
393
- this.hint = hint;
394
- this.context = context;
395
- this.apiErrorCode = apiErrorCode;
396
- if (Error.captureStackTrace) {
397
- Error.captureStackTrace(this, _CofheError);
398
- }
399
- }
400
- /**
401
- * Creates a CofheError from an unknown error
402
- * If the error is a CofheError, it is returned unchanged, else a new CofheError is created
403
- * If a wrapperError is provided, it is used to create the new CofheError, else a default is used
404
- */
405
- static fromError(error, wrapperError) {
406
- if (isCofheError(error))
407
- return error;
408
- const cause = error instanceof Error ? error : new Error(`${error}`);
409
- return new _CofheError({
410
- code: wrapperError?.code ?? "INTERNAL_ERROR" /* InternalError */,
411
- message: wrapperError?.message ?? "An internal error occurred",
412
- hint: wrapperError?.hint,
413
- context: wrapperError?.context,
414
- apiErrorCode: wrapperError?.apiErrorCode,
415
- cause
416
- });
417
- }
418
- /**
419
- * Serializes the error to JSON string with proper handling of Error objects
420
- */
421
- serialize() {
422
- return bigintSafeJsonStringify({
423
- name: this.name,
424
- code: this.code,
425
- message: this.message,
426
- hint: this.hint,
427
- context: this.context,
428
- apiErrorCode: this.apiErrorCode,
429
- cause: this.cause ? {
430
- name: this.cause.name,
431
- message: this.cause.message,
432
- stack: this.cause.stack
433
- } : void 0,
434
- stack: this.stack
435
- });
436
- }
437
- /**
438
- * Returns a human-readable string representation of the error
439
- */
440
- toString() {
441
- const codeSuffix = this.apiErrorCode ? ` (api: ${this.apiErrorCode})` : "";
442
- const parts = [`${this.name} [${this.code}]${codeSuffix}: ${this.message}`];
443
- if (this.hint) {
444
- parts.push(`Hint: ${this.hint}`);
445
- }
446
- if (this.context && Object.keys(this.context).length > 0) {
447
- parts.push(`Context: ${bigintSafeJsonStringify(this.context)}`);
448
- }
449
- if (this.stack) {
450
- parts.push(`
451
- Stack trace:`);
452
- parts.push(this.stack);
453
- }
454
- if (this.cause) {
455
- parts.push(`
456
- Caused by: ${this.cause.name}: ${this.cause.message}`);
457
- if (this.cause.stack) {
458
- parts.push(this.cause.stack);
459
- }
460
- }
461
- return parts.join("\n");
462
- }
463
- };
464
- var bigintSafeJsonStringify = (value) => {
465
- return JSON.stringify(value, (key, value2) => {
466
- if (typeof value2 === "bigint") {
467
- return `${value2}n`;
468
- }
469
- return value2;
470
- });
471
- };
472
- var isCofheError = (error) => error instanceof CofheError;
473
-
474
490
  // core/taskManager.ts
475
491
  var ADDRESS_BOOK_ABI = viem.parseAbi([
476
492
  "function getTm(uint256 id) view returns (address)",
@@ -778,15 +794,22 @@ var getAclServedAddresses = async (publicClient, chainId) => {
778
794
  } catch {
779
795
  return {};
780
796
  }
797
+ let transient = false;
798
+ const readServedAddress = (functionName) => publicClient.readContract({ address: aclAddress, abi: ACL_SERVED_ADDRESSES_ABI, functionName }).catch((err) => {
799
+ if (revertErrorName(err, ACL_SERVED_ADDRESSES_ABI) === void 0)
800
+ transient = true;
801
+ return void 0;
802
+ });
781
803
  const [defaultRevoker, shareRegistry] = await Promise.all([
782
- publicClient.readContract({ address: aclAddress, abi: ACL_SERVED_ADDRESSES_ABI, functionName: "defaultRevokerContract" }).catch(() => void 0),
783
- publicClient.readContract({ address: aclAddress, abi: ACL_SERVED_ADDRESSES_ABI, functionName: "shareRegistry" }).catch(() => void 0)
804
+ readServedAddress("defaultRevokerContract"),
805
+ readServedAddress("shareRegistry")
784
806
  ]);
785
807
  const resolved = {
786
808
  defaultRevoker: defaultRevoker != null && defaultRevoker !== viem.zeroAddress ? defaultRevoker : void 0,
787
809
  shareRegistry: shareRegistry != null && shareRegistry !== viem.zeroAddress ? shareRegistry : void 0
788
810
  };
789
- aclServedAddressesCache.set(chainId, resolved);
811
+ if (!transient)
812
+ aclServedAddressesCache.set(chainId, resolved);
790
813
  return resolved;
791
814
  };
792
815
 
@@ -1937,19 +1960,22 @@ var zkProve = async (builder, crs, metadata) => {
1937
1960
  }, 0);
1938
1961
  });
1939
1962
  };
1940
- var constructZkPoKMetadata = (accountAddr, securityZone, chainId) => {
1963
+ var constructZkPoKMetadata = (accountAddr, securityZone, chainId, consumingContract) => {
1941
1964
  const accountAddrNoPrefix = accountAddr.startsWith("0x") ? accountAddr.slice(2) : accountAddr;
1942
1965
  const accountBytes = hexToBytes(accountAddrNoPrefix);
1966
+ const contractNoPrefix = consumingContract.startsWith("0x") ? consumingContract.slice(2) : consumingContract;
1967
+ const contractBytes = hexToBytes(contractNoPrefix);
1943
1968
  const chainIdBytes = new Uint8Array(32);
1944
1969
  let value = chainId;
1945
1970
  for (let i = 31; i >= 0 && value > 0; i--) {
1946
1971
  chainIdBytes[i] = value & 255;
1947
1972
  value = value >>> 8;
1948
1973
  }
1949
- const metadata = new Uint8Array(1 + accountBytes.length + 32);
1974
+ const metadata = new Uint8Array(1 + accountBytes.length + 32 + contractBytes.length);
1950
1975
  metadata[0] = securityZone;
1951
1976
  metadata.set(accountBytes, 1);
1952
1977
  metadata.set(chainIdBytes, 1 + accountBytes.length);
1978
+ metadata.set(contractBytes, 1 + accountBytes.length + 32);
1953
1979
  return metadata;
1954
1980
  };
1955
1981
  var zkVerifyBatch = async (verifierUrl, serializedBytes, address, securityZone, chainId, consumingContract) => {
@@ -2862,20 +2888,33 @@ var EncryptInputsBuilder = class extends BaseBuilder {
2862
2888
  return this.consumingContract;
2863
2889
  }
2864
2890
  /**
2865
- * Asserts that this.consumingContract is populated
2866
- * @throws {CofheError} If consumingContract is not set
2891
+ * Asserts that this.consumingContract is populated and is an address.
2892
+ * Runs before TFHE init, key fetching and proving, so a bad address costs
2893
+ * nothing: the contract is bound into the proof, and a proof built for a
2894
+ * non-address could only fail at the verifier, after the expensive step.
2895
+ * @throws {CofheError} If consumingContract is not set or is not an address
2867
2896
  */
2868
2897
  assertConsumingContract() {
2869
- if (this.consumingContract)
2870
- return;
2871
- throw new CofheError({
2872
- code: "CONSUMING_CONTRACT_UNINITIALIZED" /* ConsumingContractUninitialized */,
2873
- message: "Consuming contract is not set",
2874
- hint: "Use setConsumingContract(...) to set the contract that will consume the encrypted inputs.",
2875
- context: {
2876
- consumingContract: this.consumingContract
2877
- }
2878
- });
2898
+ if (!this.consumingContract) {
2899
+ throw new CofheError({
2900
+ code: "CONSUMING_CONTRACT_UNINITIALIZED" /* ConsumingContractUninitialized */,
2901
+ message: "Consuming contract is not set",
2902
+ hint: "Use setConsumingContract(...) to set the contract that will consume the encrypted inputs.",
2903
+ context: {
2904
+ consumingContract: this.consumingContract
2905
+ }
2906
+ });
2907
+ }
2908
+ if (!viem.isAddress(this.consumingContract, { strict: false })) {
2909
+ throw new CofheError({
2910
+ code: "CONSUMING_CONTRACT_INVALID" /* ConsumingContractInvalid */,
2911
+ message: "Consuming contract is not an address",
2912
+ hint: "setConsumingContract(...) takes the 20-byte address of the contract that will consume the encrypted inputs.",
2913
+ context: {
2914
+ consumingContract: this.consumingContract
2915
+ }
2916
+ });
2917
+ }
2879
2918
  }
2880
2919
  setUseWorker(useWorker) {
2881
2920
  this.useWorker = useWorker;
@@ -3091,7 +3130,7 @@ var EncryptInputsBuilder = class extends BaseBuilder {
3091
3130
  zkBuilder = zkPack(this.inputItems, zkBuilder);
3092
3131
  this.fireStepEnd("pack" /* Pack */);
3093
3132
  this.fireStepStart("prove" /* Prove */);
3094
- const metadata = constructZkPoKMetadata(this.account, this.securityZone, this.chainId);
3133
+ const metadata = constructZkPoKMetadata(this.account, this.securityZone, this.chainId, this.consumingContract);
3095
3134
  let proof = null;
3096
3135
  let usedWorker = false;
3097
3136
  let workerFailedError;
package/dist/web.d.cts CHANGED
@@ -1,8 +1,8 @@
1
- import { I as IStorage, C as CofheInputConfig, a as CofheConfig, b as CofheClient, E as EncryptableItem } from './clientTypes-C0A9ji5O.cjs';
1
+ import { I as IStorage, C as CofheInputConfig, a as CofheConfig, b as CofheClient, E as EncryptableItem } from './clientTypes-C2b_qub5.cjs';
2
2
  import 'viem';
3
3
  import './types-C07FK-cL.cjs';
4
4
  import 'zod';
5
- import './onchain-utils-D9Z33IP7.cjs';
5
+ import './onchain-utils-CgOslubH.cjs';
6
6
  import 'zustand/vanilla';
7
7
 
8
8
  declare function createSsrStorage(): IStorage;
package/dist/web.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { I as IStorage, C as CofheInputConfig, a as CofheConfig, b as CofheClient, E as EncryptableItem } from './clientTypes-CcU5WvdV.js';
1
+ import { I as IStorage, C as CofheInputConfig, a as CofheConfig, b as CofheClient, E as EncryptableItem } from './clientTypes-DEKYh0cw.js';
2
2
  import 'viem';
3
3
  import './types-C07FK-cL.js';
4
4
  import 'zod';
5
- import './onchain-utils-D9Z33IP7.js';
5
+ import './onchain-utils-CgOslubH.js';
6
6
  import 'zustand/vanilla';
7
7
 
8
8
  declare function createSsrStorage(): IStorage;
package/dist/web.js CHANGED
@@ -1,9 +1,9 @@
1
- import { createCofheConfigBase, createCofheClientBase } from './chunk-OL3DZN7A.js';
1
+ import { createCofheConfigBase, createCofheClientBase } from './chunk-GKEJHZ52.js';
2
2
  import './chunk-UKQAJK4N.js';
3
- import './chunk-BQWHPIYU.js';
3
+ import './chunk-WAA2U7CT.js';
4
4
  import { initTfheThreadPool } from './chunk-KSOV5B4B.js';
5
- import { fheTypeToString, fromHexString } from './chunk-6ZW76ZKB.js';
6
- import { TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT } from './chunk-XQ32JG3T.js';
5
+ import { fheTypeToString, fromHexString } from './chunk-3SD2UCRE.js';
6
+ import { TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT } from './chunk-OC5TGQGG.js';
7
7
  import { constructClient } from 'iframe-shared-storage';
8
8
 
9
9
  // web/const.ts
@@ -1,6 +1,6 @@
1
1
  import { initTfheThreadPool } from './chunk-KSOV5B4B.js';
2
- import { fromHexString } from './chunk-6ZW76ZKB.js';
3
- import { TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT } from './chunk-XQ32JG3T.js';
2
+ import { fromHexString } from './chunk-3SD2UCRE.js';
3
+ import { TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT } from './chunk-OC5TGQGG.js';
4
4
 
5
5
  // web/zkProve.worker.ts
6
6
  var tfheModule = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cofhe/sdk",
3
- "version": "1.0.0-alpha.0",
3
+ "version": "1.0.1",
4
4
  "type": "module",
5
5
  "description": "SDK for Fhenix COFHE coprocessor interaction",
6
6
  "main": "./dist/core.cjs",