@cofhe/sdk 0.5.0 → 0.5.2

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.
@@ -27,70 +27,75 @@ function fromHexString(hexString) {
27
27
  return new Uint8Array();
28
28
  return new Uint8Array(arr.map((byte) => parseInt(byte, 16)));
29
29
  }
30
- self.onmessage = async (event) => {
31
- const { id, type, fheKeyHex, crsHex, items, metadata } = event.data;
32
- if (type !== "zkProve") {
33
- self.postMessage({
34
- id,
35
- type: "error",
36
- error: "Invalid message type"
37
- });
38
- return;
39
- }
40
- try {
41
- await initTfhe();
42
- if (!tfheModule) {
43
- throw new Error("TFHE module not initialized");
30
+ if (typeof self !== "undefined") {
31
+ self.onmessage = async (event) => {
32
+ const { id, type, fheKeyHex, crsHex, items, metadata } = event.data;
33
+ if (type !== "zkProve") {
34
+ self.postMessage({
35
+ id,
36
+ type: "error",
37
+ error: "Invalid message type"
38
+ });
39
+ return;
44
40
  }
45
- const fheKeyBytes = fromHexString(fheKeyHex);
46
- const crsBytes = fromHexString(crsHex);
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);
49
- const builder = tfheModule.ProvenCompactCiphertextList.builder(fheKey);
50
- for (const item of items) {
51
- switch (item.utype) {
52
- case "bool":
53
- builder.push_boolean(Boolean(item.data));
54
- break;
55
- case "uint8":
56
- builder.push_u8(Number(item.data));
57
- break;
58
- case "uint16":
59
- builder.push_u16(Number(item.data));
60
- break;
61
- case "uint32":
62
- builder.push_u32(Number(item.data));
63
- break;
64
- case "uint64":
65
- builder.push_u64(BigInt(item.data));
66
- break;
67
- case "uint128":
68
- builder.push_u128(BigInt(item.data));
69
- break;
70
- case "uint160":
71
- builder.push_u160(BigInt(item.data));
72
- break;
73
- default:
74
- throw new Error(`Unsupported type: ${item.utype}`);
41
+ try {
42
+ await initTfhe();
43
+ if (!tfheModule) {
44
+ throw new Error("TFHE module not initialized");
45
+ }
46
+ const fheKeyBytes = fromHexString(fheKeyHex);
47
+ const crsBytes = fromHexString(crsHex);
48
+ const fheKey = tfheModule.TfheCompactPublicKey.safe_deserialize(
49
+ fheKeyBytes,
50
+ TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT
51
+ );
52
+ const crs = tfheModule.CompactPkeCrs.safe_deserialize(crsBytes, TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
53
+ const builder = tfheModule.ProvenCompactCiphertextList.builder(fheKey);
54
+ for (const item of items) {
55
+ switch (item.utype) {
56
+ case "bool":
57
+ builder.push_boolean(Boolean(item.data));
58
+ break;
59
+ case "uint8":
60
+ builder.push_u8(Number(item.data));
61
+ break;
62
+ case "uint16":
63
+ builder.push_u16(Number(item.data));
64
+ break;
65
+ case "uint32":
66
+ builder.push_u32(Number(item.data));
67
+ break;
68
+ case "uint64":
69
+ builder.push_u64(BigInt(item.data));
70
+ break;
71
+ case "uint128":
72
+ builder.push_u128(BigInt(item.data));
73
+ break;
74
+ case "uint160":
75
+ builder.push_u160(BigInt(item.data));
76
+ break;
77
+ default:
78
+ throw new Error(`Unsupported type: ${item.utype}`);
79
+ }
75
80
  }
81
+ const metadataBytes = new Uint8Array(metadata);
82
+ const compactList = builder.build_with_proof_packed(crs, metadataBytes, 1);
83
+ const result = compactList.safe_serialize(TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
84
+ self.postMessage({
85
+ id,
86
+ type: "success",
87
+ result: Array.from(result)
88
+ });
89
+ } catch (error) {
90
+ self.postMessage({
91
+ id,
92
+ type: "error",
93
+ error: error instanceof Error ? error.message : String(error)
94
+ });
76
95
  }
77
- const metadataBytes = new Uint8Array(metadata);
78
- const compactList = builder.build_with_proof_packed(crs, metadataBytes, 1);
79
- const result = compactList.safe_serialize(TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
80
- self.postMessage({
81
- id,
82
- type: "success",
83
- result: Array.from(result)
84
- });
85
- } catch (error) {
86
- self.postMessage({
87
- id,
88
- type: "error",
89
- error: error instanceof Error ? error.message : String(error)
90
- });
91
- }
92
- };
93
- self.postMessage({
94
- id: "init",
95
- type: "ready"
96
- });
96
+ };
97
+ self.postMessage({
98
+ id: "init",
99
+ type: "ready"
100
+ });
101
+ }
@@ -24,70 +24,75 @@ function fromHexString(hexString) {
24
24
  return new Uint8Array();
25
25
  return new Uint8Array(arr.map((byte) => parseInt(byte, 16)));
26
26
  }
27
- self.onmessage = async (event) => {
28
- const { id, type, fheKeyHex, crsHex, items, metadata } = event.data;
29
- if (type !== "zkProve") {
30
- self.postMessage({
31
- id,
32
- type: "error",
33
- error: "Invalid message type"
34
- });
35
- return;
36
- }
37
- try {
38
- await initTfhe();
39
- if (!tfheModule) {
40
- throw new Error("TFHE module not initialized");
27
+ if (typeof self !== "undefined") {
28
+ self.onmessage = async (event) => {
29
+ const { id, type, fheKeyHex, crsHex, items, metadata } = event.data;
30
+ if (type !== "zkProve") {
31
+ self.postMessage({
32
+ id,
33
+ type: "error",
34
+ error: "Invalid message type"
35
+ });
36
+ return;
41
37
  }
42
- const fheKeyBytes = fromHexString(fheKeyHex);
43
- const crsBytes = fromHexString(crsHex);
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);
46
- const builder = tfheModule.ProvenCompactCiphertextList.builder(fheKey);
47
- for (const item of items) {
48
- switch (item.utype) {
49
- case "bool":
50
- builder.push_boolean(Boolean(item.data));
51
- break;
52
- case "uint8":
53
- builder.push_u8(Number(item.data));
54
- break;
55
- case "uint16":
56
- builder.push_u16(Number(item.data));
57
- break;
58
- case "uint32":
59
- builder.push_u32(Number(item.data));
60
- break;
61
- case "uint64":
62
- builder.push_u64(BigInt(item.data));
63
- break;
64
- case "uint128":
65
- builder.push_u128(BigInt(item.data));
66
- break;
67
- case "uint160":
68
- builder.push_u160(BigInt(item.data));
69
- break;
70
- default:
71
- throw new Error(`Unsupported type: ${item.utype}`);
38
+ try {
39
+ await initTfhe();
40
+ if (!tfheModule) {
41
+ throw new Error("TFHE module not initialized");
42
+ }
43
+ const fheKeyBytes = fromHexString(fheKeyHex);
44
+ const crsBytes = fromHexString(crsHex);
45
+ const fheKey = tfheModule.TfheCompactPublicKey.safe_deserialize(
46
+ fheKeyBytes,
47
+ TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT
48
+ );
49
+ const crs = tfheModule.CompactPkeCrs.safe_deserialize(crsBytes, TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
50
+ const builder = tfheModule.ProvenCompactCiphertextList.builder(fheKey);
51
+ for (const item of items) {
52
+ switch (item.utype) {
53
+ case "bool":
54
+ builder.push_boolean(Boolean(item.data));
55
+ break;
56
+ case "uint8":
57
+ builder.push_u8(Number(item.data));
58
+ break;
59
+ case "uint16":
60
+ builder.push_u16(Number(item.data));
61
+ break;
62
+ case "uint32":
63
+ builder.push_u32(Number(item.data));
64
+ break;
65
+ case "uint64":
66
+ builder.push_u64(BigInt(item.data));
67
+ break;
68
+ case "uint128":
69
+ builder.push_u128(BigInt(item.data));
70
+ break;
71
+ case "uint160":
72
+ builder.push_u160(BigInt(item.data));
73
+ break;
74
+ default:
75
+ throw new Error(`Unsupported type: ${item.utype}`);
76
+ }
72
77
  }
78
+ const metadataBytes = new Uint8Array(metadata);
79
+ const compactList = builder.build_with_proof_packed(crs, metadataBytes, 1);
80
+ const result = compactList.safe_serialize(TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
81
+ self.postMessage({
82
+ id,
83
+ type: "success",
84
+ result: Array.from(result)
85
+ });
86
+ } catch (error) {
87
+ self.postMessage({
88
+ id,
89
+ type: "error",
90
+ error: error instanceof Error ? error.message : String(error)
91
+ });
73
92
  }
74
- const metadataBytes = new Uint8Array(metadata);
75
- const compactList = builder.build_with_proof_packed(crs, metadataBytes, 1);
76
- const result = compactList.safe_serialize(TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
77
- self.postMessage({
78
- id,
79
- type: "success",
80
- result: Array.from(result)
81
- });
82
- } catch (error) {
83
- self.postMessage({
84
- id,
85
- type: "error",
86
- error: error instanceof Error ? error.message : String(error)
87
- });
88
- }
89
- };
90
- self.postMessage({
91
- id: "init",
92
- type: "ready"
93
- });
93
+ };
94
+ self.postMessage({
95
+ id: "init",
96
+ type: "ready"
97
+ });
98
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cofhe/sdk",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "type": "module",
5
5
  "description": "SDK for Fhenix COFHE coprocessor interaction",
6
6
  "main": "./dist/core.cjs",
@@ -101,8 +101,8 @@
101
101
  "tsup": "8.0.2",
102
102
  "typescript": "5.5.4",
103
103
  "vitest": "3.2.4",
104
- "@cofhe/test-setup": "0.0.0",
105
104
  "@cofhe/eslint-config": "0.2.1",
105
+ "@cofhe/test-setup": "0.0.0",
106
106
  "@cofhe/tsconfig": "0.1.2"
107
107
  },
108
108
  "publishConfig": {
package/web/index.ts CHANGED
@@ -19,8 +19,11 @@ import { createSsrStorage, createWebStorage } from './storage.js';
19
19
  // Import worker manager
20
20
  import { getWorkerManager, terminateWorker, areWorkersAvailable } from './workerManager.js';
21
21
 
22
- // Import tfhe for web
23
- import init, { init_panic_hook, TfheCompactPublicKey, ProvenCompactCiphertextList, CompactPkeCrs } from 'tfhe';
22
+ // Type-only import for tfhe — the runtime is loaded lazily via `await import('tfhe')`
23
+ // inside `initTfhe()` so that simply importing `@cofhe/sdk/web` (e.g. transitively
24
+ // through `@cofhe/react`) does not pull tfhe — and its worker helpers that
25
+ // reference `self` at module top — into the import graph during Next.js SSR.
26
+ import type { TfheCompactPublicKey, ProvenCompactCiphertextList, CompactPkeCrs } from 'tfhe';
24
27
  import { hasDOM } from './const';
25
28
 
26
29
  /**
@@ -28,15 +31,24 @@ import { hasDOM } from './const';
28
31
  * Called automatically on first encryption - users don't need to call this manually
29
32
  * @returns true if TFHE was initialized, false if already initialized
30
33
  */
34
+ let tfheModule: typeof import('tfhe') | null = null;
31
35
  let tfheInitialized = false;
32
36
  async function initTfhe(): Promise<boolean> {
33
37
  if (tfheInitialized) return false;
34
- await init();
35
- await init_panic_hook();
38
+ tfheModule = await import('tfhe');
39
+ await tfheModule.default();
40
+ await tfheModule.init_panic_hook();
36
41
  tfheInitialized = true;
37
42
  return true;
38
43
  }
39
44
 
45
+ function requireTfhe(): typeof import('tfhe') {
46
+ if (!tfheModule) {
47
+ throw new Error('TFHE not initialized — call initTfhe() (or any client method that triggers it) first');
48
+ }
49
+ return tfheModule;
50
+ }
51
+
40
52
  /**
41
53
  * Utility to convert the hex string key to a Uint8Array for use with tfhe
42
54
  */
@@ -48,11 +60,14 @@ const fromHexString = (hexString: string): Uint8Array => {
48
60
  };
49
61
 
50
62
  const _deserializeTfhePublicKey = (buff: string): TfheCompactPublicKey => {
51
- return TfheCompactPublicKey.safe_deserialize(fromHexString(buff), TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
63
+ return requireTfhe().TfheCompactPublicKey.safe_deserialize(
64
+ fromHexString(buff),
65
+ TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT
66
+ );
52
67
  };
53
68
 
54
69
  const _deserializeCompactPkeCrs = (buff: string): CompactPkeCrs => {
55
- return CompactPkeCrs.safe_deserialize(fromHexString(buff), TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
70
+ return requireTfhe().CompactPkeCrs.safe_deserialize(fromHexString(buff), TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
56
71
  };
57
72
 
58
73
  /**
@@ -77,7 +92,7 @@ const compactPkeCrsDeserializer: FheKeyDeserializer = (buff: string): void => {
77
92
  */
78
93
  const zkBuilderAndCrsGenerator: ZkBuilderAndCrsGenerator = (fhe: string, crs: string) => {
79
94
  const fhePublicKey = _deserializeTfhePublicKey(fhe);
80
- const zkBuilder = ProvenCompactCiphertextList.builder(fhePublicKey);
95
+ const zkBuilder = requireTfhe().ProvenCompactCiphertextList.builder(fhePublicKey);
81
96
  const zkCrs = _deserializeCompactPkeCrs(crs);
82
97
 
83
98
  return { zkBuilder, zkCrs };
@@ -53,10 +53,10 @@ describe('@cofhe/web - TFHE Initialization Browser Tests', () => {
53
53
  await cofheClient.connect(publicClient, walletClient);
54
54
 
55
55
  // First encryption
56
- expect(cofheClient.encryptInputs([Encryptable.uint128(100n)]).execute()).resolves.not.toThrow();
56
+ await expect(cofheClient.encryptInputs([Encryptable.uint128(100n)]).execute()).resolves.not.toThrow();
57
57
 
58
58
  // Second encryption should reuse initialization
59
- expect(cofheClient.encryptInputs([Encryptable.uint64(50n)]).execute()).resolves.not.toThrow();
60
- }, 60000);
59
+ await expect(cofheClient.encryptInputs([Encryptable.uint64(50n)]).execute()).resolves.not.toThrow();
60
+ }, 120000);
61
61
  });
62
62
  });
@@ -42,93 +42,102 @@ function fromHexString(hexString: string): Uint8Array {
42
42
  return new Uint8Array(arr.map((byte) => parseInt(byte, 16)));
43
43
  }
44
44
 
45
- /**
46
- * Main message handler
47
- */
48
- self.onmessage = async (event: MessageEvent) => {
49
- const { id, type, fheKeyHex, crsHex, items, metadata } = event.data as ZkProveWorkerRequest;
50
-
51
- if (type !== 'zkProve') {
52
- self.postMessage({
53
- id,
54
- type: 'error',
55
- error: 'Invalid message type',
56
- } as ZkProveWorkerResponse);
57
- return;
58
- }
59
-
60
- try {
61
- // Initialize TFHE if needed
62
- await initTfhe();
63
-
64
- if (!tfheModule) {
65
- throw new Error('TFHE module not initialized');
45
+ // Guard the top-level `self` references so this file is safe to evaluate in
46
+ // non-worker contexts (e.g. when bundlers like webpack pull the worker chunk
47
+ // into the server bundle for SSR). The body is dead code anywhere `self` is
48
+ // undefined, so skipping it is harmless.
49
+ if (typeof self !== 'undefined') {
50
+ /**
51
+ * Main message handler
52
+ */
53
+ self.onmessage = async (event: MessageEvent) => {
54
+ const { id, type, fheKeyHex, crsHex, items, metadata } = event.data as ZkProveWorkerRequest;
55
+
56
+ if (type !== 'zkProve') {
57
+ self.postMessage({
58
+ id,
59
+ type: 'error',
60
+ error: 'Invalid message type',
61
+ } as ZkProveWorkerResponse);
62
+ return;
66
63
  }
67
64
 
68
- // Deserialize FHE public key and CRS from hex strings
69
- const fheKeyBytes = fromHexString(fheKeyHex);
70
- const crsBytes = fromHexString(crsHex);
71
-
72
- const fheKey = tfheModule.TfheCompactPublicKey.safe_deserialize(fheKeyBytes, TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
73
- const crs = tfheModule.CompactPkeCrs.safe_deserialize(crsBytes, TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
74
-
75
- // Create builder
76
- const builder = tfheModule.ProvenCompactCiphertextList.builder(fheKey);
77
-
78
- // Pack all items (duplicate of zkPack logic)
79
- for (const item of items) {
80
- switch (item.utype) {
81
- case 'bool':
82
- builder.push_boolean(Boolean(item.data));
83
- break;
84
- case 'uint8':
85
- builder.push_u8(Number(item.data));
86
- break;
87
- case 'uint16':
88
- builder.push_u16(Number(item.data));
89
- break;
90
- case 'uint32':
91
- builder.push_u32(Number(item.data));
92
- break;
93
- case 'uint64':
94
- builder.push_u64(BigInt(item.data));
95
- break;
96
- case 'uint128':
97
- builder.push_u128(BigInt(item.data));
98
- break;
99
- case 'uint160':
100
- builder.push_u160(BigInt(item.data));
101
- break;
102
- default:
103
- throw new Error(`Unsupported type: ${item.utype}`);
104
- }
105
- }
65
+ try {
66
+ // Initialize TFHE if needed
67
+ await initTfhe();
106
68
 
107
- // THE HEAVY OPERATION - but in worker thread!
108
- const metadataBytes = new Uint8Array(metadata);
109
- const compactList = builder.build_with_proof_packed(crs, metadataBytes, 1);
69
+ if (!tfheModule) {
70
+ throw new Error('TFHE module not initialized');
71
+ }
110
72
 
111
- // Serialize result
112
- const result = compactList.safe_serialize(TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
73
+ // Deserialize FHE public key and CRS from hex strings
74
+ const fheKeyBytes = fromHexString(fheKeyHex);
75
+ const crsBytes = fromHexString(crsHex);
76
+
77
+ const fheKey = tfheModule.TfheCompactPublicKey.safe_deserialize(
78
+ fheKeyBytes,
79
+ TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT
80
+ );
81
+ const crs = tfheModule.CompactPkeCrs.safe_deserialize(crsBytes, TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
82
+
83
+ // Create builder
84
+ const builder = tfheModule.ProvenCompactCiphertextList.builder(fheKey);
85
+
86
+ // Pack all items (duplicate of zkPack logic)
87
+ for (const item of items) {
88
+ switch (item.utype) {
89
+ case 'bool':
90
+ builder.push_boolean(Boolean(item.data));
91
+ break;
92
+ case 'uint8':
93
+ builder.push_u8(Number(item.data));
94
+ break;
95
+ case 'uint16':
96
+ builder.push_u16(Number(item.data));
97
+ break;
98
+ case 'uint32':
99
+ builder.push_u32(Number(item.data));
100
+ break;
101
+ case 'uint64':
102
+ builder.push_u64(BigInt(item.data));
103
+ break;
104
+ case 'uint128':
105
+ builder.push_u128(BigInt(item.data));
106
+ break;
107
+ case 'uint160':
108
+ builder.push_u160(BigInt(item.data));
109
+ break;
110
+ default:
111
+ throw new Error(`Unsupported type: ${item.utype}`);
112
+ }
113
+ }
113
114
 
114
- // Send success response
115
- self.postMessage({
116
- id,
117
- type: 'success',
118
- result: Array.from(result),
119
- } as ZkProveWorkerResponse);
120
- } catch (error) {
121
- // Send error response
122
- self.postMessage({
123
- id,
124
- type: 'error',
125
- error: error instanceof Error ? error.message : String(error),
126
- } as ZkProveWorkerResponse);
127
- }
128
- };
115
+ // THE HEAVY OPERATION - but in worker thread!
116
+ const metadataBytes = new Uint8Array(metadata);
117
+ const compactList = builder.build_with_proof_packed(crs, metadataBytes, 1);
118
+
119
+ // Serialize result
120
+ const result = compactList.safe_serialize(TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT);
121
+
122
+ // Send success response
123
+ self.postMessage({
124
+ id,
125
+ type: 'success',
126
+ result: Array.from(result),
127
+ } as ZkProveWorkerResponse);
128
+ } catch (error) {
129
+ // Send error response
130
+ self.postMessage({
131
+ id,
132
+ type: 'error',
133
+ error: error instanceof Error ? error.message : String(error),
134
+ } as ZkProveWorkerResponse);
135
+ }
136
+ };
129
137
 
130
- // Signal ready - send proper message format
131
- self.postMessage({
132
- id: 'init',
133
- type: 'ready',
134
- } as ZkProveWorkerResponse);
138
+ // Signal ready - send proper message format
139
+ self.postMessage({
140
+ id: 'init',
141
+ type: 'ready',
142
+ } as ZkProveWorkerResponse);
143
+ }