@cofhe/sdk 0.0.0-beta-20251027110729

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 (110) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/adapters/ethers5.test.ts +174 -0
  3. package/adapters/ethers5.ts +36 -0
  4. package/adapters/ethers6.test.ts +169 -0
  5. package/adapters/ethers6.ts +36 -0
  6. package/adapters/hardhat-node.ts +167 -0
  7. package/adapters/hardhat.hh2.test.ts +159 -0
  8. package/adapters/hardhat.ts +37 -0
  9. package/adapters/index.test.ts +25 -0
  10. package/adapters/index.ts +5 -0
  11. package/adapters/smartWallet.ts +91 -0
  12. package/adapters/test-utils.ts +53 -0
  13. package/adapters/types.ts +6 -0
  14. package/adapters/wagmi.test.ts +156 -0
  15. package/adapters/wagmi.ts +17 -0
  16. package/chains/chains/arbSepolia.ts +14 -0
  17. package/chains/chains/baseSepolia.ts +14 -0
  18. package/chains/chains/hardhat.ts +15 -0
  19. package/chains/chains/sepolia.ts +14 -0
  20. package/chains/chains.test.ts +49 -0
  21. package/chains/defineChain.ts +18 -0
  22. package/chains/index.ts +33 -0
  23. package/chains/types.ts +32 -0
  24. package/core/baseBuilder.ts +138 -0
  25. package/core/client.test.ts +298 -0
  26. package/core/client.ts +308 -0
  27. package/core/config.test.ts +224 -0
  28. package/core/config.ts +213 -0
  29. package/core/decrypt/MockQueryDecrypterAbi.ts +129 -0
  30. package/core/decrypt/cofheMocksSealOutput.ts +57 -0
  31. package/core/decrypt/decryptHandleBuilder.ts +281 -0
  32. package/core/decrypt/decryptUtils.ts +28 -0
  33. package/core/decrypt/tnSealOutput.ts +59 -0
  34. package/core/encrypt/MockZkVerifierAbi.ts +106 -0
  35. package/core/encrypt/cofheMocksZkVerifySign.ts +278 -0
  36. package/core/encrypt/encryptInputsBuilder.test.ts +735 -0
  37. package/core/encrypt/encryptInputsBuilder.ts +512 -0
  38. package/core/encrypt/encryptUtils.ts +64 -0
  39. package/core/encrypt/zkPackProveVerify.ts +273 -0
  40. package/core/error.ts +170 -0
  41. package/core/fetchKeys.test.ts +212 -0
  42. package/core/fetchKeys.ts +170 -0
  43. package/core/index.ts +77 -0
  44. package/core/keyStore.test.ts +226 -0
  45. package/core/keyStore.ts +127 -0
  46. package/core/permits.test.ts +242 -0
  47. package/core/permits.ts +136 -0
  48. package/core/result.test.ts +180 -0
  49. package/core/result.ts +67 -0
  50. package/core/test-utils.ts +45 -0
  51. package/core/types.ts +352 -0
  52. package/core/utils.ts +88 -0
  53. package/dist/adapters.cjs +88 -0
  54. package/dist/adapters.d.cts +14558 -0
  55. package/dist/adapters.d.ts +14558 -0
  56. package/dist/adapters.js +83 -0
  57. package/dist/chains.cjs +101 -0
  58. package/dist/chains.d.cts +99 -0
  59. package/dist/chains.d.ts +99 -0
  60. package/dist/chains.js +1 -0
  61. package/dist/chunk-GZCQQYVI.js +93 -0
  62. package/dist/chunk-KFGPTJ6X.js +2295 -0
  63. package/dist/chunk-LU7BMUUT.js +804 -0
  64. package/dist/core.cjs +3174 -0
  65. package/dist/core.d.cts +16 -0
  66. package/dist/core.d.ts +16 -0
  67. package/dist/core.js +3 -0
  68. package/dist/node.cjs +3090 -0
  69. package/dist/node.d.cts +22 -0
  70. package/dist/node.d.ts +22 -0
  71. package/dist/node.js +90 -0
  72. package/dist/permit-S9CnI6MF.d.cts +333 -0
  73. package/dist/permit-S9CnI6MF.d.ts +333 -0
  74. package/dist/permits.cjs +856 -0
  75. package/dist/permits.d.cts +1056 -0
  76. package/dist/permits.d.ts +1056 -0
  77. package/dist/permits.js +1 -0
  78. package/dist/types-KImPrEIe.d.cts +48 -0
  79. package/dist/types-KImPrEIe.d.ts +48 -0
  80. package/dist/types-PhwGgQvs.d.ts +953 -0
  81. package/dist/types-bB7wLj0q.d.cts +953 -0
  82. package/dist/web.cjs +3067 -0
  83. package/dist/web.d.cts +22 -0
  84. package/dist/web.d.ts +22 -0
  85. package/dist/web.js +64 -0
  86. package/node/client.test.ts +152 -0
  87. package/node/config.test.ts +68 -0
  88. package/node/encryptInputs.test.ts +175 -0
  89. package/node/index.ts +96 -0
  90. package/node/storage.ts +51 -0
  91. package/package.json +120 -0
  92. package/permits/index.ts +67 -0
  93. package/permits/localstorage.test.ts +118 -0
  94. package/permits/permit.test.ts +474 -0
  95. package/permits/permit.ts +396 -0
  96. package/permits/sealing.test.ts +84 -0
  97. package/permits/sealing.ts +131 -0
  98. package/permits/signature.ts +79 -0
  99. package/permits/store.test.ts +128 -0
  100. package/permits/store.ts +168 -0
  101. package/permits/test-utils.ts +20 -0
  102. package/permits/types.ts +174 -0
  103. package/permits/utils.ts +63 -0
  104. package/permits/validation.test.ts +288 -0
  105. package/permits/validation.ts +349 -0
  106. package/web/client.web.test.ts +152 -0
  107. package/web/config.web.test.ts +71 -0
  108. package/web/encryptInputs.web.test.ts +195 -0
  109. package/web/index.ts +97 -0
  110. package/web/storage.ts +20 -0
@@ -0,0 +1,152 @@
1
+ import { type CofhesdkClient } from '@/core';
2
+ import { arbSepolia as cofhesdkArbSepolia } from '@/chains';
3
+
4
+ import { describe, it, expect, beforeAll, beforeEach, vi } from 'vitest';
5
+ import { arbitrumSepolia as viemArbitrumSepolia } from 'viem/chains';
6
+ import type { PublicClient, WalletClient } from 'viem';
7
+ import { createPublicClient, createWalletClient, http } from 'viem';
8
+ import { privateKeyToAccount } from 'viem/accounts';
9
+ import { createCofhesdkClient, createCofhesdkConfig } from './index.js';
10
+
11
+ // Real test setup - runs in browser
12
+ const TEST_PRIVATE_KEY = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80';
13
+ const TEST_ACCOUNT = privateKeyToAccount(TEST_PRIVATE_KEY).address;
14
+
15
+ describe('@cofhe/web - Client', () => {
16
+ let cofhesdkClient: CofhesdkClient;
17
+ let publicClient: PublicClient;
18
+ let walletClient: WalletClient;
19
+
20
+ beforeAll(() => {
21
+ // Create real viem clients
22
+ publicClient = createPublicClient({
23
+ chain: viemArbitrumSepolia,
24
+ transport: http(),
25
+ });
26
+
27
+ const account = privateKeyToAccount(TEST_PRIVATE_KEY);
28
+ walletClient = createWalletClient({
29
+ chain: viemArbitrumSepolia,
30
+ transport: http(),
31
+ account,
32
+ });
33
+ });
34
+
35
+ beforeEach(() => {
36
+ const config = createCofhesdkConfig({
37
+ supportedChains: [cofhesdkArbSepolia],
38
+ });
39
+ cofhesdkClient = createCofhesdkClient(config);
40
+ });
41
+
42
+ describe('Browser Client Initialization', () => {
43
+ it('should create a client with real tfhe for browser', () => {
44
+ expect(cofhesdkClient).toBeDefined();
45
+ expect(cofhesdkClient.config).toBeDefined();
46
+ expect(cofhesdkClient.connected).toBe(false);
47
+ });
48
+
49
+ it('should automatically use IndexedDB storage as default', () => {
50
+ expect(cofhesdkClient.config.fheKeyStorage).toBeDefined();
51
+ expect(cofhesdkClient.config.fheKeyStorage).not.toBeNull();
52
+ });
53
+
54
+ it('should have all expected methods', () => {
55
+ expect(typeof cofhesdkClient.connect).toBe('function');
56
+ expect(typeof cofhesdkClient.encryptInputs).toBe('function');
57
+ expect(typeof cofhesdkClient.decryptHandle).toBe('function');
58
+ expect(typeof cofhesdkClient.getSnapshot).toBe('function');
59
+ expect(typeof cofhesdkClient.subscribe).toBe('function');
60
+ });
61
+ });
62
+
63
+ describe('Connection', () => {
64
+ it('should connect to real chain', async () => {
65
+ const result = await cofhesdkClient.connect(publicClient, walletClient);
66
+
67
+ expect(result.success).toBe(true);
68
+ expect(cofhesdkClient.connected).toBe(true);
69
+
70
+ const snapshot = cofhesdkClient.getSnapshot();
71
+ expect(snapshot.connected).toBe(true);
72
+ expect(snapshot.chainId).toBe(cofhesdkArbSepolia.id);
73
+ expect(snapshot.account).toBe(TEST_ACCOUNT);
74
+ }, 30000);
75
+
76
+ it('should handle network errors', async () => {
77
+ const result = await cofhesdkClient.connect(
78
+ {
79
+ getChainId: vi.fn().mockRejectedValue(new Error('Network error')),
80
+ } as unknown as PublicClient,
81
+ walletClient
82
+ );
83
+
84
+ expect(result.success).toBe(false);
85
+ expect(cofhesdkClient.connected).toBe(false);
86
+ }, 30000);
87
+ });
88
+
89
+ describe('State Management', () => {
90
+ it('should track connection state changes', async () => {
91
+ const states: any[] = [];
92
+ const unsubscribe = cofhesdkClient.subscribe((snapshot) => {
93
+ states.push({ ...snapshot });
94
+ });
95
+
96
+ await cofhesdkClient.connect(publicClient, walletClient);
97
+
98
+ unsubscribe();
99
+
100
+ expect(states.length).toBeGreaterThan(0);
101
+
102
+ // First state should be connecting
103
+ const firstState = states.find((s) => s.connecting);
104
+ expect(firstState).toBeDefined();
105
+ expect(firstState?.connecting).toBe(true);
106
+ expect(firstState?.connected).toBe(false);
107
+
108
+ // Last state should be connected
109
+ const lastState = states[states.length - 1];
110
+ expect(lastState.connected).toBe(true);
111
+ expect(lastState.connecting).toBe(false);
112
+ expect(lastState.chainId).toBe(cofhesdkArbSepolia.id);
113
+ }, 30000);
114
+ });
115
+
116
+ describe('Initialization Results', () => {
117
+ it('should have keyFetchResult promise', () => {
118
+ expect(cofhesdkClient.initializationResults).toBeDefined();
119
+ expect(cofhesdkClient.initializationResults.keyFetchResult).toBeInstanceOf(Promise);
120
+ });
121
+
122
+ it('should resolve keyFetchResult', async () => {
123
+ const result = await cofhesdkClient.initializationResults.keyFetchResult;
124
+ expect(result.success).toBe(true);
125
+ });
126
+ });
127
+
128
+ describe('Builder Creation', () => {
129
+ it('should create encrypt builder after connection', async () => {
130
+ await cofhesdkClient.connect(publicClient, walletClient);
131
+
132
+ const builder = cofhesdkClient.encryptInputs([{ data: 100n, utype: 2 }]);
133
+
134
+ expect(builder).toBeDefined();
135
+ expect(typeof builder.setChainId).toBe('function');
136
+ expect(typeof builder.setAccount).toBe('function');
137
+ expect(typeof builder.setSecurityZone).toBe('function');
138
+ expect(typeof builder.encrypt).toBe('function');
139
+ }, 30000);
140
+
141
+ it('should create decrypt builder after connection', async () => {
142
+ await cofhesdkClient.connect(publicClient, walletClient);
143
+
144
+ const builder = cofhesdkClient.decryptHandle(123n, 2);
145
+
146
+ expect(builder).toBeDefined();
147
+ expect(typeof builder.setChainId).toBe('function');
148
+ expect(typeof builder.setAccount).toBe('function');
149
+ expect(typeof builder.decrypt).toBe('function');
150
+ }, 30000);
151
+ });
152
+ });
@@ -0,0 +1,71 @@
1
+ import { arbSepolia } from '@/chains';
2
+
3
+ import { describe, it, expect } from 'vitest';
4
+ import { createCofhesdkConfig, createCofhesdkClient } from './index.js';
5
+
6
+ describe('@cofhe/web - Config', () => {
7
+ describe('createCofhesdkConfig', () => {
8
+ it('should automatically inject IndexedDB storage as default', () => {
9
+ const config = createCofhesdkConfig({
10
+ supportedChains: [arbSepolia],
11
+ });
12
+
13
+ expect(config.fheKeyStorage).toBeDefined();
14
+ expect(config.fheKeyStorage).not.toBeNull();
15
+ expect(config.supportedChains).toEqual([arbSepolia]);
16
+ });
17
+
18
+ it('should allow overriding storage', async () => {
19
+ const customStorage = {
20
+ getItem: () => Promise.resolve(10),
21
+ setItem: () => Promise.resolve(),
22
+ removeItem: () => Promise.resolve(),
23
+ };
24
+
25
+ const config = createCofhesdkConfig({
26
+ supportedChains: [arbSepolia],
27
+ fheKeyStorage: customStorage,
28
+ });
29
+
30
+ expect(await config.fheKeyStorage!.getItem('test')).toBe(10);
31
+ });
32
+
33
+ it('should allow null storage', () => {
34
+ const config = createCofhesdkConfig({
35
+ supportedChains: [arbSepolia],
36
+ fheKeyStorage: null,
37
+ });
38
+
39
+ expect(config.fheKeyStorage).toBeNull();
40
+ });
41
+
42
+ it('should preserve all other config options', () => {
43
+ const config = createCofhesdkConfig({
44
+ supportedChains: [arbSepolia],
45
+ fheKeysPrefetching: 'OFF',
46
+ mocks: {
47
+ sealOutputDelay: 500,
48
+ },
49
+ });
50
+
51
+ expect(config.supportedChains).toEqual([arbSepolia]);
52
+ expect(config.fheKeysPrefetching).toBe('OFF');
53
+ expect(config.mocks.sealOutputDelay).toBe(500);
54
+ expect(config.fheKeyStorage).toBeDefined();
55
+ });
56
+ });
57
+
58
+ describe('createCofhesdkClient with config', () => {
59
+ it('should create client with validated config', () => {
60
+ const config = createCofhesdkConfig({
61
+ supportedChains: [arbSepolia],
62
+ });
63
+
64
+ const client = createCofhesdkClient(config);
65
+
66
+ expect(client).toBeDefined();
67
+ expect(client.config).toBe(config);
68
+ expect(client.config.fheKeyStorage).toBeDefined();
69
+ });
70
+ });
71
+ });
@@ -0,0 +1,195 @@
1
+ import { arbSepolia as cofhesdkArbSepolia } from '@/chains';
2
+ import { Encryptable, FheTypes, type CofhesdkClient, type Result, CofhesdkErrorCode, CofhesdkError } from '@/core';
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 { createCofhesdkClient, createCofhesdkConfig } from './index.js';
10
+
11
+ // Real test setup - runs in browser with real tfhe
12
+ const TEST_PRIVATE_KEY = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80';
13
+
14
+ const expectResultSuccess = <T>(result: Result<T>): T => {
15
+ expect(result.success, `Result error: ${result.error?.toString()}`).toBe(true);
16
+ return result.data!;
17
+ };
18
+
19
+ const expectResultError = <T>(result: Result<T>, errorCode?: CofhesdkErrorCode): void => {
20
+ expect(result.success).toBe(false);
21
+ expect(result.data).toBe(null);
22
+ expect(result.error).not.toBe(null);
23
+ const error = result.error as CofhesdkError;
24
+ expect(error).toBeInstanceOf(CofhesdkError);
25
+ if (errorCode) {
26
+ expect(error.code, `Result error: ${result.error?.toString()}`).toBe(errorCode);
27
+ }
28
+ };
29
+
30
+ describe('@cofhe/web - Encrypt Inputs Browser Tests', () => {
31
+ let cofhesdkClient: CofhesdkClient;
32
+ let publicClient: PublicClient;
33
+ let walletClient: WalletClient;
34
+
35
+ beforeAll(() => {
36
+ // Create real viem clients
37
+ publicClient = createPublicClient({
38
+ chain: viemArbitrumSepolia,
39
+ transport: http(),
40
+ });
41
+
42
+ const account = privateKeyToAccount(TEST_PRIVATE_KEY);
43
+ walletClient = createWalletClient({
44
+ chain: viemArbitrumSepolia,
45
+ transport: http(),
46
+ account,
47
+ });
48
+ });
49
+
50
+ beforeEach(() => {
51
+ const config = createCofhesdkConfig({
52
+ supportedChains: [cofhesdkArbSepolia],
53
+ });
54
+ cofhesdkClient = createCofhesdkClient(config);
55
+ });
56
+
57
+ describe('Browser TFHE Initialization', () => {
58
+ it('should initialize tfhe on first encryption', async () => {
59
+ await cofhesdkClient.connect(publicClient, walletClient);
60
+
61
+ // This will trigger real TFHE initialization in browser
62
+ const result = await cofhesdkClient.encryptInputs([Encryptable.uint128(100n)]).encrypt();
63
+ const encrypted = expectResultSuccess(result);
64
+
65
+ // If we get here, TFHE was initialized successfully
66
+ expect(encrypted).toBeDefined();
67
+ }, 60000); // Longer timeout for real operations
68
+
69
+ it('should handle multiple encryptions without re-initializing', async () => {
70
+ await cofhesdkClient.connect(publicClient, walletClient);
71
+
72
+ // First encryption
73
+ const result1 = await cofhesdkClient.encryptInputs([Encryptable.uint128(100n)]).encrypt();
74
+ expectResultSuccess(result1);
75
+
76
+ // Second encryption should reuse initialization
77
+ const result2 = await cofhesdkClient.encryptInputs([Encryptable.uint64(50n)]).encrypt();
78
+ expectResultSuccess(result2);
79
+ }, 60000);
80
+ });
81
+
82
+ describe('Browser Encryption', () => {
83
+ it('should encrypt a bool with real TFHE in browser', async () => {
84
+ await cofhesdkClient.connect(publicClient, walletClient);
85
+
86
+ const result = await cofhesdkClient.encryptInputs([Encryptable.bool(true)]).encrypt();
87
+ const encrypted = expectResultSuccess(result);
88
+
89
+ expect(encrypted.length).toBe(1);
90
+ expect(encrypted[0].utype).toBe(FheTypes.Bool);
91
+ expect(encrypted[0].ctHash).toBeDefined();
92
+ expect(typeof encrypted[0].ctHash).toBe('bigint');
93
+ expect(encrypted[0].signature).toBeDefined();
94
+ expect(typeof encrypted[0].signature).toBe('string');
95
+ expect(encrypted[0].securityZone).toBe(0);
96
+ }, 60000);
97
+
98
+ it('should encrypt all supported types together', async () => {
99
+ await cofhesdkClient.connect(publicClient, walletClient);
100
+
101
+ const inputs = [
102
+ Encryptable.bool(false),
103
+ Encryptable.uint8(1n),
104
+ Encryptable.uint16(2n),
105
+ Encryptable.uint32(3n),
106
+ Encryptable.uint64(4n),
107
+ Encryptable.uint128(5n),
108
+ Encryptable.address('0x742d35Cc6634C0532925a3b844D16faC4c175E99'),
109
+ ];
110
+
111
+ const result = await cofhesdkClient.encryptInputs(inputs).encrypt();
112
+ const encrypted = expectResultSuccess(result);
113
+
114
+ expect(encrypted.length).toBe(7);
115
+ // Verify each type
116
+ expect(encrypted[0].utype).toBe(FheTypes.Bool);
117
+ expect(encrypted[1].utype).toBe(FheTypes.Uint8);
118
+ expect(encrypted[2].utype).toBe(FheTypes.Uint16);
119
+ expect(encrypted[3].utype).toBe(FheTypes.Uint32);
120
+ expect(encrypted[4].utype).toBe(FheTypes.Uint64);
121
+ expect(encrypted[5].utype).toBe(FheTypes.Uint128);
122
+ expect(encrypted[6].utype).toBe(FheTypes.Uint160);
123
+ }, 90000); // Longer timeout for multiple encryptions
124
+ });
125
+
126
+ describe('Browser Builder Pattern', () => {
127
+ it('should support chaining builder methods with real encryption', async () => {
128
+ await cofhesdkClient.connect(publicClient, walletClient);
129
+
130
+ const snapshot = cofhesdkClient.getSnapshot();
131
+ const result = await cofhesdkClient
132
+ .encryptInputs([Encryptable.uint128(100n)])
133
+ .setChainId(snapshot.chainId!)
134
+ .setAccount(snapshot.account!)
135
+ .setSecurityZone(0)
136
+ .encrypt();
137
+
138
+ const encrypted = expectResultSuccess(result);
139
+ expect(encrypted.length).toBe(1);
140
+ expect(encrypted[0].utype).toBe(FheTypes.Uint128);
141
+ }, 60000);
142
+ });
143
+
144
+ describe('Browser Error Handling', () => {
145
+ it('should fail gracefully when not connected', async () => {
146
+ // Don't connect the client
147
+ const result = await cofhesdkClient.encryptInputs([Encryptable.uint128(100n)]).encrypt();
148
+
149
+ expectResultError(result, CofhesdkErrorCode.NotConnected);
150
+ }, 30000);
151
+
152
+ it('should handle invalid CoFHE URL', async () => {
153
+ const badConfig = createCofhesdkConfig({
154
+ supportedChains: [
155
+ {
156
+ ...cofhesdkArbSepolia,
157
+ coFheUrl: 'http://invalid-cofhe-url.local',
158
+ verifierUrl: 'http://invalid-verifier-url.local',
159
+ },
160
+ ],
161
+ fheKeysPrefetching: 'OFF',
162
+ });
163
+
164
+ const badClient = createCofhesdkClient(badConfig);
165
+ await badClient.connect(publicClient, walletClient);
166
+
167
+ const result = await badClient.encryptInputs([Encryptable.uint128(100n)]).encrypt();
168
+
169
+ expect(result.success).toBe(false);
170
+ if (!result.success) {
171
+ expect(result.error).toBeDefined();
172
+ }
173
+ }, 60000);
174
+ });
175
+
176
+ describe('Browser Performance', () => {
177
+ it('should handle consecutive encryptions efficiently', async () => {
178
+ await cofhesdkClient.connect(publicClient, walletClient);
179
+
180
+ const start = Date.now();
181
+
182
+ // Perform 5 encryptions
183
+ for (let i = 0; i < 5; i++) {
184
+ const result = await cofhesdkClient.encryptInputs([Encryptable.uint128(BigInt(i))]).encrypt();
185
+ expectResultSuccess(result);
186
+ }
187
+
188
+ const duration = Date.now() - start;
189
+
190
+ // Should complete all 5 encryptions in reasonable time
191
+ // This is a sanity check, not a strict benchmark
192
+ expect(duration).toBeLessThan(120000); // 2 minutes max
193
+ }, 180000); // 3 minute timeout
194
+ });
195
+ });
package/web/index.ts ADDED
@@ -0,0 +1,97 @@
1
+ // Web specific functionality only
2
+
3
+ import {
4
+ createCofhesdkClientBase,
5
+ createCofhesdkConfigBase,
6
+ type CofhesdkClient,
7
+ type CofhesdkConfig,
8
+ type CofhesdkInputConfig,
9
+ type ZkBuilderAndCrsGenerator,
10
+ type FheKeyDeserializer,
11
+ } from '@/core';
12
+
13
+ // Import web-specific storage (internal use only)
14
+ import { createWebStorage } from './storage.js';
15
+
16
+ // Import tfhe for web
17
+ import init, { init_panic_hook, TfheCompactPublicKey, ProvenCompactCiphertextList, CompactPkeCrs } from 'tfhe';
18
+
19
+ /**
20
+ * Internal function to initialize TFHE for web
21
+ * Called automatically on first encryption - users don't need to call this manually
22
+ * @returns true if TFHE was initialized, false if already initialized
23
+ */
24
+ let tfheInitialized = false;
25
+ async function initTfhe(): Promise<boolean> {
26
+ if (tfheInitialized) return false;
27
+ await init();
28
+ await init_panic_hook();
29
+ tfheInitialized = true;
30
+ return true;
31
+ }
32
+
33
+ /**
34
+ * Utility to convert the hex string key to a Uint8Array for use with tfhe
35
+ */
36
+ const fromHexString = (hexString: string): Uint8Array => {
37
+ const cleanString = hexString.length % 2 === 1 ? `0${hexString}` : hexString;
38
+ const arr = cleanString.replace(/^0x/, '').match(/.{1,2}/g);
39
+ if (!arr) return new Uint8Array();
40
+ return new Uint8Array(arr.map((byte) => parseInt(byte, 16)));
41
+ };
42
+
43
+ /**
44
+ * Serializer for TFHE public keys
45
+ * Validates that the buffer can be deserialized into a TfheCompactPublicKey
46
+ */
47
+ const tfhePublicKeyDeserializer: FheKeyDeserializer = (buff: string): void => {
48
+ TfheCompactPublicKey.deserialize(fromHexString(buff));
49
+ };
50
+
51
+ /**
52
+ * Serializer for Compact PKE CRS
53
+ * Validates that the buffer can be deserialized into ZkCompactPkePublicParams
54
+ */
55
+ const compactPkeCrsDeserializer: FheKeyDeserializer = (buff: string): void => {
56
+ CompactPkeCrs.deserialize(fromHexString(buff));
57
+ };
58
+
59
+ /**
60
+ * Creates a ZK builder and CRS from FHE public key and CRS buffers
61
+ * This is used internally by the SDK to create encrypted inputs
62
+ */
63
+ const zkBuilderAndCrsGenerator: ZkBuilderAndCrsGenerator = (fhe: string, crs: string) => {
64
+ const fhePublicKey = TfheCompactPublicKey.deserialize(fromHexString(fhe));
65
+ const zkBuilder = ProvenCompactCiphertextList.builder(fhePublicKey);
66
+ const zkCrs = CompactPkeCrs.deserialize(fromHexString(crs));
67
+
68
+ return { zkBuilder, zkCrs };
69
+ };
70
+
71
+ /**
72
+ * Creates a CoFHE SDK configuration for web with IndexedDB storage as default
73
+ * @param config - The CoFHE SDK input configuration (fheKeyStorage will default to IndexedDB if not provided)
74
+ * @returns The CoFHE SDK configuration with web defaults applied
75
+ */
76
+ export function createCofhesdkConfig(config: CofhesdkInputConfig): CofhesdkConfig {
77
+ return createCofhesdkConfigBase({
78
+ ...config,
79
+ fheKeyStorage: config.fheKeyStorage === null ? null : config.fheKeyStorage ?? createWebStorage(),
80
+ });
81
+ }
82
+
83
+ /**
84
+ * Creates a CoFHE SDK client instance for web with TFHE automatically configured
85
+ * TFHE will be initialized automatically on first encryption - no manual setup required
86
+ * @param config - The CoFHE SDK configuration (use createCofhesdkConfig to create with web defaults)
87
+ * @returns The CoFHE SDK client instance
88
+ */
89
+ export function createCofhesdkClient(config: CofhesdkConfig): CofhesdkClient {
90
+ return createCofhesdkClientBase({
91
+ config,
92
+ zkBuilderAndCrsGenerator,
93
+ tfhePublicKeyDeserializer,
94
+ compactPkeCrsDeserializer,
95
+ initTfhe,
96
+ });
97
+ }
package/web/storage.ts ADDED
@@ -0,0 +1,20 @@
1
+ import type { IStorage } from '@/core';
2
+ import { get, set, del } from 'idb-keyval';
3
+
4
+ /**
5
+ * Creates a web storage implementation using IndexedDB
6
+ * @returns IStorage implementation for browser environments
7
+ */
8
+ export const createWebStorage = (): IStorage => {
9
+ return {
10
+ getItem: async (name: string) => {
11
+ return (await get(name)) || null;
12
+ },
13
+ setItem: async (name: string, value: any) => {
14
+ await set(name, value);
15
+ },
16
+ removeItem: async (name: string) => {
17
+ await del(name);
18
+ },
19
+ };
20
+ };