@cofhe/sdk 0.4.0 → 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.
Files changed (95) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/adapters/{ethers5.test.ts → test/ethers5.test.ts} +2 -2
  3. package/adapters/{ethers6.test.ts → test/ethers6.test.ts} +2 -2
  4. package/adapters/{hardhat.hh2.test.ts → test/hardhat.hh2.test.ts} +2 -2
  5. package/adapters/{index.test.ts → test/index.test.ts} +1 -1
  6. package/adapters/{wagmi.test.ts → test/wagmi.test.ts} +1 -1
  7. package/chains/{chains.test.ts → test/chains.test.ts} +1 -1
  8. package/core/client.ts +11 -1
  9. package/core/clientTypes.ts +3 -1
  10. package/core/consts.ts +9 -0
  11. package/core/decrypt/cofheMocksDecryptForTx.ts +14 -3
  12. package/core/decrypt/decryptForTxBuilder.ts +16 -2
  13. package/core/decrypt/decryptForViewBuilder.ts +14 -7
  14. package/core/decrypt/polling.ts +14 -0
  15. package/core/decrypt/tnDecryptV2.ts +250 -110
  16. package/core/decrypt/tnSealOutputV2.ts +245 -104
  17. package/core/decrypt/verifyDecryptResult.ts +65 -0
  18. package/core/encrypt/cofheMocksZkVerifySign.ts +6 -6
  19. package/core/encrypt/zkPackProveVerify.ts +10 -19
  20. package/core/fetchKeys.ts +0 -2
  21. package/core/index.ts +9 -1
  22. package/core/keyStore.ts +5 -2
  23. package/core/permits.ts +5 -0
  24. package/core/{client.test.ts → test/client.test.ts} +7 -7
  25. package/core/{config.test.ts → test/config.test.ts} +1 -1
  26. package/core/test/decrypt.test.ts +252 -0
  27. package/core/test/decryptBuilders.test.ts +390 -0
  28. package/core/{encrypt → test}/encryptInputsBuilder.test.ts +61 -6
  29. package/core/{fetchKeys.test.ts → test/fetchKeys.test.ts} +3 -3
  30. package/core/{keyStore.test.ts → test/keyStore.test.ts} +5 -3
  31. package/core/{permits.test.ts → test/permits.test.ts} +42 -1
  32. package/core/test/pollCallbacks.test.ts +563 -0
  33. package/core/types.ts +13 -0
  34. package/dist/chains.d.cts +2 -2
  35. package/dist/chains.d.ts +2 -2
  36. package/dist/chunk-4FP4V35O.js +13 -0
  37. package/dist/{chunk-NWDKXBIP.js → chunk-MRCKUMOS.js} +62 -22
  38. package/dist/{chunk-MXND5SVN.js → chunk-S7OKGLFD.js} +485 -207
  39. package/dist/{clientTypes-kkrRdawm.d.ts → clientTypes-BSbwairE.d.cts} +23 -6
  40. package/dist/{clientTypes-ACVWbrXL.d.cts → clientTypes-DDmcgZ0a.d.ts} +23 -6
  41. package/dist/core.cjs +561 -244
  42. package/dist/core.d.cts +24 -6
  43. package/dist/core.d.ts +24 -6
  44. package/dist/core.js +3 -2
  45. package/dist/node.cjs +566 -246
  46. package/dist/node.d.cts +3 -3
  47. package/dist/node.d.ts +3 -3
  48. package/dist/node.js +14 -7
  49. package/dist/{permit-MZ502UBl.d.cts → permit-DnVMDT5h.d.cts} +34 -4
  50. package/dist/{permit-MZ502UBl.d.ts → permit-DnVMDT5h.d.ts} +34 -4
  51. package/dist/permits.cjs +66 -29
  52. package/dist/permits.d.cts +18 -13
  53. package/dist/permits.d.ts +18 -13
  54. package/dist/permits.js +2 -1
  55. package/dist/web.cjs +588 -251
  56. package/dist/web.d.cts +8 -4
  57. package/dist/web.d.ts +8 -4
  58. package/dist/web.js +34 -11
  59. package/dist/zkProve.worker.cjs +6 -3
  60. package/dist/zkProve.worker.js +5 -3
  61. package/node/index.ts +13 -4
  62. package/node/test/client.test.ts +25 -0
  63. package/node/test/config.test.ts +16 -0
  64. package/node/test/inherited.test.ts +244 -0
  65. package/node/test/tfheinit.test.ts +56 -0
  66. package/package.json +24 -22
  67. package/permits/permit.ts +31 -5
  68. package/permits/sealing.ts +1 -1
  69. package/permits/{localstorage.test.ts → test/localstorage.test.ts} +2 -2
  70. package/permits/{permit.test.ts → test/permit.test.ts} +35 -1
  71. package/permits/{sealing.test.ts → test/sealing.test.ts} +1 -1
  72. package/permits/{store.test.ts → test/store.test.ts} +2 -2
  73. package/permits/{validation.test.ts → test/validation.test.ts} +82 -6
  74. package/permits/types.ts +1 -1
  75. package/permits/validation.ts +42 -2
  76. package/web/const.ts +2 -0
  77. package/web/index.ts +20 -6
  78. package/web/storage.ts +18 -3
  79. package/web/{client.web.test.ts → test/client.web.test.ts} +13 -1
  80. package/web/test/config.web.test.ts +16 -0
  81. package/web/test/inherited.web.test.ts +245 -0
  82. package/web/test/tfheinit.web.test.ts +62 -0
  83. package/web/{worker.config.web.test.ts → test/worker.config.web.test.ts} +1 -1
  84. package/web/{worker.output.web.test.ts → test/worker.output.web.test.ts} +1 -1
  85. package/web/{workerManager.test.ts → test/workerManager.test.ts} +1 -1
  86. package/web/{workerManager.web.test.ts → test/workerManager.web.test.ts} +1 -1
  87. package/web/zkProve.worker.ts +4 -3
  88. package/node/client.test.ts +0 -147
  89. package/node/config.test.ts +0 -68
  90. package/node/encryptInputs.test.ts +0 -155
  91. package/web/config.web.test.ts +0 -69
  92. package/web/encryptInputs.web.test.ts +0 -172
  93. package/web/worker.builder.web.test.ts +0 -148
  94. /package/dist/{types-YiAC4gig.d.cts → types-C07FK-cL.d.cts} +0 -0
  95. /package/dist/{types-YiAC4gig.d.ts → types-C07FK-cL.d.ts} +0 -0
package/dist/web.d.cts CHANGED
@@ -1,10 +1,12 @@
1
- import { C as CofheInputConfig, a as CofheConfig, b as CofheClient, E as EncryptableItem } from './clientTypes-ACVWbrXL.cjs';
1
+ import { I as IStorage, C as CofheInputConfig, a as CofheConfig, b as CofheClient, E as EncryptableItem } from './clientTypes-BSbwairE.cjs';
2
2
  import 'viem';
3
- import './types-YiAC4gig.cjs';
3
+ import './types-C07FK-cL.cjs';
4
4
  import 'zod';
5
- import './permit-MZ502UBl.cjs';
5
+ import './permit-DnVMDT5h.cjs';
6
6
  import 'zustand/vanilla';
7
7
 
8
+ declare function createSsrStorage(): IStorage;
9
+
8
10
  /**
9
11
  * Terminate the worker
10
12
  */
@@ -14,6 +16,8 @@ declare function terminateWorker(): void;
14
16
  */
15
17
  declare function areWorkersAvailable(): boolean;
16
18
 
19
+ declare const hasDOM: boolean;
20
+
17
21
  /**
18
22
  * Creates a CoFHE configuration for web with IndexedDB storage as default
19
23
  * @param config - The CoFHE input configuration (fheKeyStorage will default to IndexedDB if not provided)
@@ -35,4 +39,4 @@ declare function createCofheClient<TConfig extends CofheConfig>(config: TConfig)
35
39
  */
36
40
  declare function createCofheClientWithCustomWorker(config: CofheConfig, customZkProveWorkerFn: (fheKeyHex: string, crsHex: string, items: EncryptableItem[], metadata: Uint8Array) => Promise<Uint8Array>): CofheClient;
37
41
 
38
- export { areWorkersAvailable, createCofheClient, createCofheClientWithCustomWorker, createCofheConfig, terminateWorker };
42
+ export { areWorkersAvailable, createCofheClient, createCofheClientWithCustomWorker, createCofheConfig, createSsrStorage, hasDOM, terminateWorker };
package/dist/web.d.ts CHANGED
@@ -1,10 +1,12 @@
1
- import { C as CofheInputConfig, a as CofheConfig, b as CofheClient, E as EncryptableItem } from './clientTypes-kkrRdawm.js';
1
+ import { I as IStorage, C as CofheInputConfig, a as CofheConfig, b as CofheClient, E as EncryptableItem } from './clientTypes-DDmcgZ0a.js';
2
2
  import 'viem';
3
- import './types-YiAC4gig.js';
3
+ import './types-C07FK-cL.js';
4
4
  import 'zod';
5
- import './permit-MZ502UBl.js';
5
+ import './permit-DnVMDT5h.js';
6
6
  import 'zustand/vanilla';
7
7
 
8
+ declare function createSsrStorage(): IStorage;
9
+
8
10
  /**
9
11
  * Terminate the worker
10
12
  */
@@ -14,6 +16,8 @@ declare function terminateWorker(): void;
14
16
  */
15
17
  declare function areWorkersAvailable(): boolean;
16
18
 
19
+ declare const hasDOM: boolean;
20
+
17
21
  /**
18
22
  * Creates a CoFHE configuration for web with IndexedDB storage as default
19
23
  * @param config - The CoFHE input configuration (fheKeyStorage will default to IndexedDB if not provided)
@@ -35,4 +39,4 @@ declare function createCofheClient<TConfig extends CofheConfig>(config: TConfig)
35
39
  */
36
40
  declare function createCofheClientWithCustomWorker(config: CofheConfig, customZkProveWorkerFn: (fheKeyHex: string, crsHex: string, items: EncryptableItem[], metadata: Uint8Array) => Promise<Uint8Array>): CofheClient;
37
41
 
38
- export { areWorkersAvailable, createCofheClient, createCofheClientWithCustomWorker, createCofheConfig, terminateWorker };
42
+ export { areWorkersAvailable, createCofheClient, createCofheClientWithCustomWorker, createCofheConfig, createSsrStorage, hasDOM, terminateWorker };
package/dist/web.js CHANGED
@@ -1,15 +1,22 @@
1
- import { createCofheConfigBase, createCofheClientBase, fheTypeToString } from './chunk-MXND5SVN.js';
1
+ import { createCofheConfigBase, createCofheClientBase, fheTypeToString } from './chunk-S7OKGLFD.js';
2
2
  import './chunk-TBLR7NNE.js';
3
- import './chunk-NWDKXBIP.js';
3
+ import './chunk-MRCKUMOS.js';
4
+ import { TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT } from './chunk-4FP4V35O.js';
4
5
  import { constructClient } from 'iframe-shared-storage';
5
- import init, { init_panic_hook, TfheCompactPublicKey, CompactPkeCrs, ProvenCompactCiphertextList } from 'tfhe';
6
+ import init, { init_panic_hook, ProvenCompactCiphertextList, CompactPkeCrs, TfheCompactPublicKey } from 'tfhe';
6
7
 
7
- var createWebStorage = () => {
8
+ // web/const.ts
9
+ var hasDOM = typeof globalThis?.document !== "undefined" && typeof globalThis?.window !== "undefined";
10
+
11
+ // web/storage.ts
12
+ var createWebStorage = (opts = { enableLog: false }) => {
13
+ if (!hasDOM)
14
+ throw new Error("createWebStorage can only be used in a browser environment");
8
15
  const client = constructClient({
9
16
  iframe: {
10
17
  src: "https://iframe-shared-storage.vercel.app/hub.html",
11
18
  messagingOptions: {
12
- enableLog: "both"
19
+ enableLog: opts.enableLog ? "both" : void 0
13
20
  },
14
21
  iframeReadyTimeoutMs: 3e4,
15
22
  // if the iframe is not initied during this interval AND a reuqest is made, such request will throw an error
@@ -32,6 +39,16 @@ var createWebStorage = () => {
32
39
  }
33
40
  };
34
41
  };
42
+ function createSsrStorage() {
43
+ console.warn("using no-op server-side SSR storage");
44
+ return {
45
+ getItem: async () => null,
46
+ setItem: async () => {
47
+ },
48
+ removeItem: async () => {
49
+ }
50
+ };
51
+ }
35
52
 
36
53
  // web/workerManager.ts
37
54
  var ZkProveWorkerManager = class {
@@ -187,16 +204,22 @@ var fromHexString = (hexString) => {
187
204
  return new Uint8Array();
188
205
  return new Uint8Array(arr.map((byte) => parseInt(byte, 16)));
189
206
  };
207
+ var _deserializeTfhePublicKey = (buff) => {
208
+ return TfheCompactPublicKey.safe_deserialize(fromHexString(buff), TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
209
+ };
210
+ var _deserializeCompactPkeCrs = (buff) => {
211
+ return CompactPkeCrs.safe_deserialize(fromHexString(buff), TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
212
+ };
190
213
  var tfhePublicKeyDeserializer = (buff) => {
191
- TfheCompactPublicKey.deserialize(fromHexString(buff));
214
+ _deserializeTfhePublicKey(buff);
192
215
  };
193
216
  var compactPkeCrsDeserializer = (buff) => {
194
- CompactPkeCrs.deserialize(fromHexString(buff));
217
+ _deserializeCompactPkeCrs(buff);
195
218
  };
196
219
  var zkBuilderAndCrsGenerator = (fhe, crs) => {
197
- const fhePublicKey = TfheCompactPublicKey.deserialize(fromHexString(fhe));
220
+ const fhePublicKey = _deserializeTfhePublicKey(fhe);
198
221
  const zkBuilder = ProvenCompactCiphertextList.builder(fhePublicKey);
199
- const zkCrs = CompactPkeCrs.deserialize(fromHexString(crs));
222
+ const zkCrs = _deserializeCompactPkeCrs(crs);
200
223
  return { zkBuilder, zkCrs };
201
224
  };
202
225
  async function zkProveWithWorker(fheKeyHex, crsHex, items, metadata) {
@@ -211,7 +234,7 @@ function createCofheConfig(config) {
211
234
  return createCofheConfigBase({
212
235
  environment: "web",
213
236
  ...config,
214
- fheKeyStorage: config.fheKeyStorage === null ? null : config.fheKeyStorage ?? createWebStorage()
237
+ fheKeyStorage: config.fheKeyStorage === null ? null : config.fheKeyStorage ?? (hasDOM ? createWebStorage() : createSsrStorage())
215
238
  });
216
239
  }
217
240
  function createCofheClient(config) {
@@ -237,4 +260,4 @@ function createCofheClientWithCustomWorker(config, customZkProveWorkerFn) {
237
260
  });
238
261
  }
239
262
 
240
- export { areWorkersAvailable, createCofheClient, createCofheClientWithCustomWorker, createCofheConfig, terminateWorker };
263
+ export { areWorkersAvailable, createCofheClient, createCofheClientWithCustomWorker, createCofheConfig, createSsrStorage, hasDOM, terminateWorker };
@@ -1,5 +1,8 @@
1
1
  'use strict';
2
2
 
3
+ // core/consts.ts
4
+ var TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT = BigInt(1 << 30);
5
+
3
6
  // web/zkProve.worker.ts
4
7
  var tfheModule = null;
5
8
  var initialized = false;
@@ -41,8 +44,8 @@ self.onmessage = async (event) => {
41
44
  }
42
45
  const fheKeyBytes = fromHexString(fheKeyHex);
43
46
  const crsBytes = fromHexString(crsHex);
44
- const fheKey = tfheModule.TfheCompactPublicKey.deserialize(fheKeyBytes);
45
- const crs = tfheModule.CompactPkeCrs.deserialize(crsBytes);
47
+ const fheKey = tfheModule.TfheCompactPublicKey.safe_deserialize(fheKeyBytes, TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
48
+ const crs = tfheModule.CompactPkeCrs.safe_deserialize(crsBytes, TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
46
49
  const builder = tfheModule.ProvenCompactCiphertextList.builder(fheKey);
47
50
  for (const item of items) {
48
51
  switch (item.utype) {
@@ -73,7 +76,7 @@ self.onmessage = async (event) => {
73
76
  }
74
77
  const metadataBytes = new Uint8Array(metadata);
75
78
  const compactList = builder.build_with_proof_packed(crs, metadataBytes, 1);
76
- const result = compactList.serialize();
79
+ const result = compactList.safe_serialize(TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
77
80
  self.postMessage({
78
81
  id,
79
82
  type: "success",
@@ -1,3 +1,5 @@
1
+ import { TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT } from './chunk-4FP4V35O.js';
2
+
1
3
  // web/zkProve.worker.ts
2
4
  var tfheModule = null;
3
5
  var initialized = false;
@@ -39,8 +41,8 @@ self.onmessage = async (event) => {
39
41
  }
40
42
  const fheKeyBytes = fromHexString(fheKeyHex);
41
43
  const crsBytes = fromHexString(crsHex);
42
- const fheKey = tfheModule.TfheCompactPublicKey.deserialize(fheKeyBytes);
43
- const crs = tfheModule.CompactPkeCrs.deserialize(crsBytes);
44
+ const fheKey = tfheModule.TfheCompactPublicKey.safe_deserialize(fheKeyBytes, TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
45
+ const crs = tfheModule.CompactPkeCrs.safe_deserialize(crsBytes, TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
44
46
  const builder = tfheModule.ProvenCompactCiphertextList.builder(fheKey);
45
47
  for (const item of items) {
46
48
  switch (item.utype) {
@@ -71,7 +73,7 @@ self.onmessage = async (event) => {
71
73
  }
72
74
  const metadataBytes = new Uint8Array(metadata);
73
75
  const compactList = builder.build_with_proof_packed(crs, metadataBytes, 1);
74
- const result = compactList.serialize();
76
+ const result = compactList.safe_serialize(TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
75
77
  self.postMessage({
76
78
  id,
77
79
  type: "success",
package/node/index.ts CHANGED
@@ -8,6 +8,7 @@ import {
8
8
  type CofheInputConfig,
9
9
  type ZkBuilderAndCrsGenerator,
10
10
  type FheKeyDeserializer,
11
+ TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT,
11
12
  } from '@/core';
12
13
 
13
14
  // Import node-specific storage (internal use only)
@@ -39,12 +40,20 @@ const fromHexString = (hexString: string): Uint8Array => {
39
40
  return new Uint8Array(arr.map((byte) => parseInt(byte, 16)));
40
41
  };
41
42
 
43
+ const _deserializeTfhePublicKey = (buff: string): TfheCompactPublicKey => {
44
+ return TfheCompactPublicKey.safe_deserialize(fromHexString(buff), TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
45
+ };
46
+
47
+ const _deserializeCompactPkeCrs = (buff: string): CompactPkeCrs => {
48
+ return CompactPkeCrs.safe_deserialize(fromHexString(buff), TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
49
+ };
50
+
42
51
  /**
43
52
  * Serializer for TFHE public keys
44
53
  * Validates that the buffer can be deserialized into a TfheCompactPublicKey
45
54
  */
46
55
  const tfhePublicKeyDeserializer: FheKeyDeserializer = (buff: string): void => {
47
- TfheCompactPublicKey.deserialize(fromHexString(buff));
56
+ _deserializeTfhePublicKey(buff);
48
57
  };
49
58
 
50
59
  /**
@@ -52,7 +61,7 @@ const tfhePublicKeyDeserializer: FheKeyDeserializer = (buff: string): void => {
52
61
  * Validates that the buffer can be deserialized into ZkCompactPkePublicParams
53
62
  */
54
63
  const compactPkeCrsDeserializer: FheKeyDeserializer = (buff: string): void => {
55
- CompactPkeCrs.deserialize(fromHexString(buff));
64
+ _deserializeCompactPkeCrs(buff);
56
65
  };
57
66
 
58
67
  /**
@@ -60,9 +69,9 @@ const compactPkeCrsDeserializer: FheKeyDeserializer = (buff: string): void => {
60
69
  * This is used internally by the SDK to create encrypted inputs
61
70
  */
62
71
  const zkBuilderAndCrsGenerator: ZkBuilderAndCrsGenerator = (fhe: string, crs: string) => {
63
- const fhePublicKey = TfheCompactPublicKey.deserialize(fromHexString(fhe));
72
+ const fhePublicKey = _deserializeTfhePublicKey(fhe);
64
73
  const zkBuilder = ProvenCompactCiphertextList.builder(fhePublicKey);
65
- const zkCrs = CompactPkeCrs.deserialize(fromHexString(crs));
74
+ const zkCrs = _deserializeCompactPkeCrs(crs);
66
75
 
67
76
  return { zkBuilder, zkCrs };
68
77
  };
@@ -0,0 +1,25 @@
1
+ import { type CofheClient } from '@/core';
2
+ import { arbSepolia as cofheArbSepolia } from '@/chains';
3
+
4
+ import { describe, it, expect, beforeEach } from 'vitest';
5
+ import { createCofheClient, createCofheConfig } from '../index.js';
6
+
7
+ describe('@cofhe/node - Client', () => {
8
+ let cofheClient: CofheClient;
9
+
10
+ beforeEach(() => {
11
+ const config = createCofheConfig({
12
+ supportedChains: [cofheArbSepolia],
13
+ });
14
+ cofheClient = createCofheClient(config);
15
+ });
16
+
17
+ it('should automatically use filesystem storage as default', () => {
18
+ expect(cofheClient.config.fheKeyStorage).toBeDefined();
19
+ expect(cofheClient.config.fheKeyStorage).not.toBeNull();
20
+ });
21
+
22
+ it('should have the correct environment', () => {
23
+ expect(cofheClient.config.environment).toBe('node');
24
+ });
25
+ });
@@ -0,0 +1,16 @@
1
+ import { arbSepolia } from '@/chains';
2
+
3
+ import { describe, it, expect } from 'vitest';
4
+ import { createCofheConfig } from '../index.js';
5
+
6
+ describe('@cofhe/node - Config', () => {
7
+ it('should automatically inject filesystem storage as default', () => {
8
+ const config = createCofheConfig({
9
+ supportedChains: [arbSepolia],
10
+ });
11
+
12
+ expect(config.fheKeyStorage).toBeDefined();
13
+ expect(config.fheKeyStorage).not.toBeNull();
14
+ expect(config.supportedChains).toEqual([arbSepolia]);
15
+ });
16
+ });
@@ -0,0 +1,244 @@
1
+ import { Encryptable, FheTypes, type CofheClient } from '@/core';
2
+ import { arbSepolia as cofheArbSepolia, getChainById } from '@/chains';
3
+ import {
4
+ TEST_PRIVATE_KEY,
5
+ PRIMARY_TEST_CHAIN,
6
+ primaryTestChainRegistry,
7
+ isPrimaryTestChainReady,
8
+ } from '@cofhe/test-setup';
9
+
10
+ import { describe, it, expect, beforeAll, beforeEach } from 'vitest';
11
+ import type { Chain, PublicClient, WalletClient } from 'viem';
12
+ import { createPublicClient, createWalletClient, http } from 'viem';
13
+ import { privateKeyToAccount } from 'viem/accounts';
14
+ import { arbitrumSepolia, baseSepolia, sepolia } from 'viem/chains';
15
+ import { createCofheClient, createCofheConfig } from '../index.js';
16
+
17
+ const DEFAULT_TEST_PRIVATE_KEY = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80';
18
+ const BOB_PRIVATE_KEY = (TEST_PRIVATE_KEY || DEFAULT_TEST_PRIVATE_KEY) as `0x${string}`;
19
+ const ALICE_PRIVATE_KEY = '0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d';
20
+
21
+ const bobAccount = privateKeyToAccount(BOB_PRIVATE_KEY);
22
+ const aliceAccount = privateKeyToAccount(ALICE_PRIVATE_KEY);
23
+
24
+ const VIEM_CHAINS: Record<number, Chain> = {
25
+ 421614: arbitrumSepolia,
26
+ 84532: baseSepolia,
27
+ 11155111: sepolia,
28
+ };
29
+
30
+ describe('@cofhe/node - Inherited Client Tests', () => {
31
+ let cofheClient: CofheClient;
32
+ let publicClient: PublicClient;
33
+ let bobWalletClient: WalletClient;
34
+ let aliceWalletClient: WalletClient;
35
+
36
+ beforeAll(() => {
37
+ publicClient = createPublicClient({
38
+ chain: arbitrumSepolia,
39
+ transport: http(),
40
+ });
41
+
42
+ bobWalletClient = createWalletClient({
43
+ chain: arbitrumSepolia,
44
+ transport: http(),
45
+ account: bobAccount,
46
+ });
47
+
48
+ aliceWalletClient = createWalletClient({
49
+ chain: arbitrumSepolia,
50
+ transport: http(),
51
+ account: aliceAccount,
52
+ });
53
+ });
54
+
55
+ beforeEach(() => {
56
+ const config = createCofheConfig({
57
+ supportedChains: [cofheArbSepolia],
58
+ });
59
+ cofheClient = createCofheClient(config);
60
+ });
61
+
62
+ describe('Client Creation', () => {
63
+ it('should create a client with expected surface', () => {
64
+ expect(cofheClient).toBeDefined();
65
+ expect(cofheClient.config).toBeDefined();
66
+ expect(cofheClient.connected).toBe(false);
67
+ expect(typeof cofheClient.connect).toBe('function');
68
+ expect(typeof cofheClient.disconnect).toBe('function');
69
+ expect(typeof cofheClient.encryptInputs).toBe('function');
70
+ expect(typeof cofheClient.decryptForView).toBe('function');
71
+ expect(typeof cofheClient.decryptForTx).toBe('function');
72
+ expect(typeof cofheClient.getSnapshot).toBe('function');
73
+ expect(typeof cofheClient.subscribe).toBe('function');
74
+ expect(cofheClient.permits).toBeDefined();
75
+ });
76
+ });
77
+
78
+ describe('Connection', () => {
79
+ it('should connect to a real chain', async () => {
80
+ await cofheClient.connect(publicClient, bobWalletClient);
81
+
82
+ expect(cofheClient.connected).toBe(true);
83
+
84
+ const snapshot = cofheClient.getSnapshot();
85
+ expect(snapshot.connected).toBe(true);
86
+ expect(snapshot.chainId).toBe(cofheArbSepolia.id);
87
+ expect(snapshot.account).toBe(bobAccount.address);
88
+ }, 30000);
89
+ });
90
+
91
+ describe('Encrypt Input', () => {
92
+ it('should encrypt a uint128 value', async () => {
93
+ await cofheClient.connect(publicClient, bobWalletClient);
94
+
95
+ const encrypted = await cofheClient.encryptInputs([Encryptable.uint128(100n)]).execute();
96
+
97
+ expect(encrypted).toBeDefined();
98
+ expect(encrypted.length).toBe(1);
99
+ expect(encrypted[0].utype).toBe(FheTypes.Uint128);
100
+ expect(encrypted[0].ctHash).toBeDefined();
101
+ expect(typeof encrypted[0].ctHash).toBe('bigint');
102
+ expect(encrypted[0].signature).toBeDefined();
103
+ expect(typeof encrypted[0].signature).toBe('string');
104
+ expect(encrypted[0].securityZone).toBe(0);
105
+ }, 60000);
106
+ });
107
+
108
+ describe('Self Permit', () => {
109
+ it('should create a self permit', async () => {
110
+ await cofheClient.connect(publicClient, bobWalletClient);
111
+
112
+ const permit = await cofheClient.permits.createSelf({
113
+ issuer: bobAccount.address,
114
+ name: 'Test Self Permit',
115
+ });
116
+
117
+ expect(permit).toBeDefined();
118
+ expect(permit.type).toBe('self');
119
+ expect(permit.name).toBe('Test Self Permit');
120
+ expect(permit.issuer).toBe(bobAccount.address);
121
+ expect(permit.issuerSignature).not.toBe('0x');
122
+ expect(permit.sealingPair).toBeDefined();
123
+ expect(permit.sealingPair.publicKey).toBeDefined();
124
+
125
+ const activePermit = cofheClient.permits.getActivePermit();
126
+ expect(activePermit).toBeDefined();
127
+ expect(activePermit!.hash).toBe(permit.hash);
128
+ }, 30000);
129
+ });
130
+
131
+ describe('Sharing Permit', () => {
132
+ it('should create a sharing permit, export it, and import it as another user', async () => {
133
+ await cofheClient.connect(publicClient, bobWalletClient);
134
+
135
+ const sharingPermit = await cofheClient.permits.createSharing({
136
+ issuer: bobAccount.address,
137
+ recipient: aliceAccount.address,
138
+ name: 'Test Sharing Permit',
139
+ });
140
+
141
+ expect(sharingPermit).toBeDefined();
142
+ expect(sharingPermit.type).toBe('sharing');
143
+ expect(sharingPermit.issuer).toBe(bobAccount.address);
144
+ expect(sharingPermit.recipient).toBe(aliceAccount.address);
145
+ expect(sharingPermit.issuerSignature).not.toBe('0x');
146
+
147
+ const exported = cofheClient.permits.export(sharingPermit);
148
+ expect(exported).toBeDefined();
149
+ const parsed = JSON.parse(exported);
150
+ expect(parsed.type).toBe('sharing');
151
+ expect(parsed.issuer).toBe(bobAccount.address);
152
+ expect(parsed.recipient).toBe(aliceAccount.address);
153
+ expect(parsed.issuerSignature).toBeDefined();
154
+ expect(parsed).not.toHaveProperty('sealingPair');
155
+
156
+ const aliceConfig = createCofheConfig({
157
+ supportedChains: [cofheArbSepolia],
158
+ });
159
+ const aliceClient = createCofheClient(aliceConfig);
160
+ await aliceClient.connect(publicClient, aliceWalletClient);
161
+
162
+ const importedPermit = await aliceClient.permits.importShared(exported);
163
+
164
+ expect(importedPermit).toBeDefined();
165
+ expect(importedPermit.type).toBe('recipient');
166
+ expect(importedPermit.issuer).toBe(bobAccount.address);
167
+ expect(importedPermit.recipient).toBe(aliceAccount.address);
168
+ expect(importedPermit.recipientSignature).not.toBe('0x');
169
+ expect(importedPermit.sealingPair).toBeDefined();
170
+ }, 30000);
171
+ });
172
+
173
+ describe('Decrypt (read-only, pre-stored values)', () => {
174
+ let decryptClient: CofheClient;
175
+ let decryptPublicClient: PublicClient;
176
+ let decryptWalletClient: WalletClient;
177
+
178
+ let privateCtHash: `0x${string}`;
179
+ let privateValue: bigint;
180
+ let publicCtHash: `0x${string}`;
181
+ let publicValue: bigint;
182
+
183
+ beforeAll(() => {
184
+ if (!isPrimaryTestChainReady(primaryTestChainRegistry)) {
185
+ throw new Error('Primary test chain registry not initialized. Run `pnpm test:setup` first.');
186
+ }
187
+
188
+ const reg = primaryTestChainRegistry;
189
+ const viemChain = VIEM_CHAINS[reg.chainId];
190
+ if (!viemChain) throw new Error(`No viem chain mapping for chain ${reg.chainId}`);
191
+
192
+ const cofheChain = getChainById(reg.chainId);
193
+ if (!cofheChain) throw new Error(`No cofhe chain config for chain ${reg.chainId}`);
194
+
195
+ privateCtHash = reg.privateValue.ctHash as `0x${string}`;
196
+ privateValue = BigInt(reg.privateValue.value);
197
+ publicCtHash = reg.publicValue.ctHash as `0x${string}`;
198
+ publicValue = BigInt(reg.publicValue.value);
199
+
200
+ decryptPublicClient = createPublicClient({ chain: viemChain, transport: http() });
201
+ decryptWalletClient = createWalletClient({ chain: viemChain, transport: http(), account: bobAccount });
202
+
203
+ const config = createCofheConfig({ supportedChains: [cofheChain] });
204
+ decryptClient = createCofheClient(config);
205
+ });
206
+
207
+ it('decryptForView — private value with permit', async () => {
208
+ await decryptClient.connect(decryptPublicClient, decryptWalletClient);
209
+
210
+ await decryptClient.permits.createSelf({
211
+ issuer: bobAccount.address,
212
+ name: 'Decrypt View Permit',
213
+ });
214
+
215
+ const result = await decryptClient.decryptForView(privateCtHash, FheTypes.Uint32).execute();
216
+ expect(result).toBe(privateValue);
217
+ }, 180000);
218
+
219
+ it('decryptForTx — public value without permit', async () => {
220
+ await decryptClient.connect(decryptPublicClient, decryptWalletClient);
221
+
222
+ const result = await decryptClient.decryptForTx(publicCtHash).withoutPermit().execute();
223
+
224
+ expect(BigInt(result.ctHash)).toBe(BigInt(publicCtHash));
225
+ expect(result.decryptedValue).toBe(publicValue);
226
+ expect(result.signature).toMatch(/^0x[0-9a-fA-F]+$/);
227
+ }, 180000);
228
+
229
+ it('decryptForTx — private value with permit', async () => {
230
+ await decryptClient.connect(decryptPublicClient, decryptWalletClient);
231
+
232
+ const permit = await decryptClient.permits.createSelf({
233
+ issuer: bobAccount.address,
234
+ name: 'Decrypt Tx Permit',
235
+ });
236
+
237
+ const result = await decryptClient.decryptForTx(privateCtHash).withPermit(permit).execute();
238
+
239
+ expect(BigInt(result.ctHash)).toBe(BigInt(privateCtHash));
240
+ expect(result.decryptedValue).toBe(privateValue);
241
+ expect(result.signature).toBeDefined();
242
+ }, 180000);
243
+ });
244
+ });
@@ -0,0 +1,56 @@
1
+ import { Encryptable, type CofheClient } from '@/core';
2
+ import { arbSepolia as cofheArbSepolia } from '@/chains';
3
+
4
+ import { describe, it, expect, beforeAll, beforeEach } from 'vitest';
5
+ import type { PublicClient, WalletClient } from 'viem';
6
+ import { createPublicClient, createWalletClient, http } from 'viem';
7
+ import { privateKeyToAccount } from 'viem/accounts';
8
+ import { arbitrumSepolia as viemArbitrumSepolia } from 'viem/chains';
9
+ import { createCofheClient, createCofheConfig } from '../index.js';
10
+
11
+ const TEST_PRIVATE_KEY = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80';
12
+
13
+ describe('@cofhe/node - TFHE Initialization Tests', () => {
14
+ let cofheClient: CofheClient;
15
+ let publicClient: PublicClient;
16
+ let walletClient: WalletClient;
17
+
18
+ beforeAll(() => {
19
+ publicClient = createPublicClient({
20
+ chain: viemArbitrumSepolia,
21
+ transport: http(),
22
+ });
23
+
24
+ const account = privateKeyToAccount(TEST_PRIVATE_KEY);
25
+ walletClient = createWalletClient({
26
+ chain: viemArbitrumSepolia,
27
+ transport: http(),
28
+ account,
29
+ });
30
+ });
31
+
32
+ beforeEach(() => {
33
+ const config = createCofheConfig({
34
+ supportedChains: [cofheArbSepolia],
35
+ });
36
+ cofheClient = createCofheClient(config);
37
+ });
38
+
39
+ describe('Node TFHE Initialization', () => {
40
+ it('should initialize node-tfhe on first encryption', async () => {
41
+ await cofheClient.connect(publicClient, walletClient);
42
+
43
+ const result = await cofheClient.encryptInputs([Encryptable.uint128(100n)]).execute();
44
+
45
+ expect(result).toBeDefined();
46
+ }, 60000);
47
+
48
+ it('should handle multiple encryptions without re-initializing', async () => {
49
+ await cofheClient.connect(publicClient, walletClient);
50
+
51
+ await cofheClient.encryptInputs([Encryptable.uint128(100n)]).execute();
52
+
53
+ await cofheClient.encryptInputs([Encryptable.uint64(50n)]).execute();
54
+ }, 120000);
55
+ });
56
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cofhe/sdk",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
5
  "description": "SDK for Fhenix COFHE coprocessor interaction",
6
6
  "main": "./dist/core.cjs",
@@ -57,14 +57,14 @@
57
57
  "CHANGELOG.md"
58
58
  ],
59
59
  "dependencies": {
60
- "iframe-shared-storage": "^1.0.34",
61
- "immer": "^10.1.1",
62
- "node-tfhe": "0.11.1",
63
- "tfhe": "0.11.1",
64
- "tweetnacl": "^1.0.3",
65
- "viem": "^2.38.6",
66
- "zod": "^4.0.0",
67
- "zustand": "^5.0.1"
60
+ "iframe-shared-storage": "1.0.34",
61
+ "immer": "10.1.1",
62
+ "node-tfhe": "1.5.3",
63
+ "tfhe": "1.5.3",
64
+ "tweetnacl": "1.0.3",
65
+ "viem": "2.38.6",
66
+ "zod": "4.0.0",
67
+ "zustand": "5.0.1"
68
68
  },
69
69
  "peerDependencies": {
70
70
  "@nomicfoundation/hardhat-ethers": "^3.0.0",
@@ -88,24 +88,26 @@
88
88
  }
89
89
  },
90
90
  "devDependencies": {
91
- "@nomicfoundation/hardhat-ethers": "^3.0.0",
92
- "@types/node": "^20.0.0",
93
- "@vitest/browser": "^3.0.0",
94
- "@vitest/coverage-v8": "^3.0.0",
95
- "eslint": "^8.57.0",
96
- "ethers5": "npm:ethers@^5.7.2",
97
- "ethers6": "npm:ethers@^6.13.0",
98
- "happy-dom": "^15.0.0",
99
- "hardhat": "^2.19.0",
100
- "playwright": "^1.55.0",
101
- "tsup": "^8.0.2",
91
+ "@nomicfoundation/hardhat-ethers": "3.1.0",
92
+ "@types/node": "20.19.15",
93
+ "@vitest/browser": "3.2.4",
94
+ "@vitest/coverage-v8": "3.2.4",
95
+ "eslint": "8.57.1",
96
+ "ethers5": "npm:ethers@5.8.0",
97
+ "ethers6": "npm:ethers@6.15.0",
98
+ "happy-dom": "15.11.7",
99
+ "hardhat": "2.26.3",
100
+ "playwright": "1.55.0",
101
+ "tsup": "8.0.2",
102
102
  "typescript": "5.5.4",
103
- "vitest": "^3.0.0",
103
+ "vitest": "3.2.4",
104
+ "@cofhe/test-setup": "0.0.0",
104
105
  "@cofhe/eslint-config": "0.2.1",
105
106
  "@cofhe/tsconfig": "0.1.2"
106
107
  },
107
108
  "publishConfig": {
108
- "access": "public"
109
+ "access": "public",
110
+ "registry": "https://registry.npmjs.org/"
109
111
  },
110
112
  "scripts": {
111
113
  "build": "tsup",