@cofhe/sdk 0.0.0-alpha-20260409113701
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.
- package/CHANGELOG.md +146 -0
- package/adapters/ethers5.test.ts +174 -0
- package/adapters/ethers5.ts +36 -0
- package/adapters/ethers6.test.ts +169 -0
- package/adapters/ethers6.ts +36 -0
- package/adapters/hardhat-node.ts +167 -0
- package/adapters/hardhat.hh2.test.ts +159 -0
- package/adapters/hardhat.ts +36 -0
- package/adapters/index.test.ts +20 -0
- package/adapters/index.ts +5 -0
- package/adapters/smartWallet.ts +99 -0
- package/adapters/test-utils.ts +53 -0
- package/adapters/types.ts +6 -0
- package/adapters/wagmi.test.ts +156 -0
- package/adapters/wagmi.ts +17 -0
- package/chains/chains/arbSepolia.ts +14 -0
- package/chains/chains/baseSepolia.ts +14 -0
- package/chains/chains/hardhat.ts +15 -0
- package/chains/chains/localcofhe.ts +14 -0
- package/chains/chains/sepolia.ts +14 -0
- package/chains/chains.test.ts +50 -0
- package/chains/defineChain.ts +18 -0
- package/chains/index.ts +35 -0
- package/chains/types.ts +32 -0
- package/core/baseBuilder.ts +119 -0
- package/core/client.test.ts +429 -0
- package/core/client.ts +341 -0
- package/core/clientTypes.ts +119 -0
- package/core/config.test.ts +242 -0
- package/core/config.ts +225 -0
- package/core/consts.ts +22 -0
- package/core/decrypt/MockThresholdNetworkAbi.ts +179 -0
- package/core/decrypt/cofheMocksDecryptForTx.ts +84 -0
- package/core/decrypt/cofheMocksDecryptForView.ts +48 -0
- package/core/decrypt/decryptForTxBuilder.ts +359 -0
- package/core/decrypt/decryptForViewBuilder.ts +332 -0
- package/core/decrypt/decryptUtils.ts +28 -0
- package/core/decrypt/pollCallbacks.test.ts +194 -0
- package/core/decrypt/polling.ts +14 -0
- package/core/decrypt/tnDecryptUtils.ts +65 -0
- package/core/decrypt/tnDecryptV1.ts +171 -0
- package/core/decrypt/tnDecryptV2.ts +365 -0
- package/core/decrypt/tnSealOutputV1.ts +59 -0
- package/core/decrypt/tnSealOutputV2.ts +324 -0
- package/core/decrypt/verifyDecryptResult.ts +52 -0
- package/core/encrypt/MockZkVerifierAbi.ts +106 -0
- package/core/encrypt/cofheMocksZkVerifySign.ts +281 -0
- package/core/encrypt/encryptInputsBuilder.test.ts +747 -0
- package/core/encrypt/encryptInputsBuilder.ts +583 -0
- package/core/encrypt/encryptUtils.ts +67 -0
- package/core/encrypt/zkPackProveVerify.ts +335 -0
- package/core/error.ts +168 -0
- package/core/fetchKeys.test.ts +195 -0
- package/core/fetchKeys.ts +144 -0
- package/core/index.ts +106 -0
- package/core/keyStore.test.ts +226 -0
- package/core/keyStore.ts +154 -0
- package/core/permits.test.ts +493 -0
- package/core/permits.ts +201 -0
- package/core/types.ts +419 -0
- package/core/utils.ts +130 -0
- package/dist/adapters.cjs +88 -0
- package/dist/adapters.d.cts +14576 -0
- package/dist/adapters.d.ts +14576 -0
- package/dist/adapters.js +83 -0
- package/dist/chains.cjs +111 -0
- package/dist/chains.d.cts +121 -0
- package/dist/chains.d.ts +121 -0
- package/dist/chains.js +1 -0
- package/dist/chunk-36FBWLUS.js +3310 -0
- package/dist/chunk-7HLGHV67.js +990 -0
- package/dist/chunk-TBLR7NNE.js +102 -0
- package/dist/clientTypes-AVSCBet7.d.cts +998 -0
- package/dist/clientTypes-flH1ju82.d.ts +998 -0
- package/dist/core.cjs +4362 -0
- package/dist/core.d.cts +138 -0
- package/dist/core.d.ts +138 -0
- package/dist/core.js +3 -0
- package/dist/node.cjs +4225 -0
- package/dist/node.d.cts +22 -0
- package/dist/node.d.ts +22 -0
- package/dist/node.js +91 -0
- package/dist/permit-jRirYqFt.d.cts +376 -0
- package/dist/permit-jRirYqFt.d.ts +376 -0
- package/dist/permits.cjs +1025 -0
- package/dist/permits.d.cts +353 -0
- package/dist/permits.d.ts +353 -0
- package/dist/permits.js +1 -0
- package/dist/types-YiAC4gig.d.cts +33 -0
- package/dist/types-YiAC4gig.d.ts +33 -0
- package/dist/web.cjs +4434 -0
- package/dist/web.d.cts +42 -0
- package/dist/web.d.ts +42 -0
- package/dist/web.js +256 -0
- package/dist/zkProve.worker.cjs +93 -0
- package/dist/zkProve.worker.d.cts +2 -0
- package/dist/zkProve.worker.d.ts +2 -0
- package/dist/zkProve.worker.js +91 -0
- package/node/client.test.ts +159 -0
- package/node/config.test.ts +68 -0
- package/node/encryptInputs.test.ts +155 -0
- package/node/index.ts +97 -0
- package/node/storage.ts +51 -0
- package/package.json +121 -0
- package/permits/index.ts +68 -0
- package/permits/localstorage.test.ts +113 -0
- package/permits/onchain-utils.ts +221 -0
- package/permits/permit.test.ts +534 -0
- package/permits/permit.ts +386 -0
- package/permits/sealing.test.ts +84 -0
- package/permits/sealing.ts +131 -0
- package/permits/signature.ts +79 -0
- package/permits/store.test.ts +88 -0
- package/permits/store.ts +156 -0
- package/permits/test-utils.ts +28 -0
- package/permits/types.ts +204 -0
- package/permits/utils.ts +58 -0
- package/permits/validation.test.ts +361 -0
- package/permits/validation.ts +327 -0
- package/web/client.web.test.ts +159 -0
- package/web/config.web.test.ts +69 -0
- package/web/const.ts +2 -0
- package/web/encryptInputs.web.test.ts +172 -0
- package/web/index.ts +166 -0
- package/web/storage.ts +49 -0
- package/web/worker.builder.web.test.ts +148 -0
- package/web/worker.config.web.test.ts +329 -0
- package/web/worker.output.web.test.ts +84 -0
- package/web/workerManager.test.ts +80 -0
- package/web/workerManager.ts +214 -0
- package/web/workerManager.web.test.ts +114 -0
- package/web/zkProve.worker.ts +133 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { arbSepolia } from '@/chains';
|
|
2
|
+
|
|
3
|
+
import { describe, it, expect } from 'vitest';
|
|
4
|
+
import { createCofheConfig, createCofheClient } from './index.js';
|
|
5
|
+
|
|
6
|
+
describe('@cofhe/node - Config', () => {
|
|
7
|
+
describe('createCofheConfig', () => {
|
|
8
|
+
it('should automatically inject filesystem storage as default', () => {
|
|
9
|
+
const config = createCofheConfig({
|
|
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
|
+
const config = createCofheConfig({
|
|
25
|
+
supportedChains: [arbSepolia],
|
|
26
|
+
fheKeyStorage: customStorage,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
expect(await config.fheKeyStorage!.getItem('test')).toBe(10);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should allow null storage', () => {
|
|
33
|
+
const config = createCofheConfig({
|
|
34
|
+
supportedChains: [arbSepolia],
|
|
35
|
+
fheKeyStorage: null,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
expect(config.fheKeyStorage).toBeNull();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should preserve all other config options', () => {
|
|
42
|
+
const config = createCofheConfig({
|
|
43
|
+
supportedChains: [arbSepolia],
|
|
44
|
+
mocks: {
|
|
45
|
+
decryptDelay: 0,
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
expect(config.supportedChains).toEqual([arbSepolia]);
|
|
50
|
+
expect(config.mocks.decryptDelay).toBe(0);
|
|
51
|
+
expect(config.fheKeyStorage).toBeDefined();
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('createCofheClient with config', () => {
|
|
56
|
+
it('should create client with validated config', () => {
|
|
57
|
+
const config = createCofheConfig({
|
|
58
|
+
supportedChains: [arbSepolia],
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const client = createCofheClient(config);
|
|
62
|
+
|
|
63
|
+
expect(client).toBeDefined();
|
|
64
|
+
expect(client.config).toBe(config);
|
|
65
|
+
expect(client.config.fheKeyStorage).toBeDefined();
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
});
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { Encryptable, FheTypes, type CofheClient, CofheErrorCode, CofheError } 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
|
+
// Real test setup - using actual node-tfhe
|
|
12
|
+
const TEST_PRIVATE_KEY = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80';
|
|
13
|
+
|
|
14
|
+
describe('@cofhe/node - Encrypt Inputs', () => {
|
|
15
|
+
let cofheClient: CofheClient;
|
|
16
|
+
let publicClient: PublicClient;
|
|
17
|
+
let walletClient: WalletClient;
|
|
18
|
+
|
|
19
|
+
beforeAll(() => {
|
|
20
|
+
// Create real viem clients
|
|
21
|
+
publicClient = createPublicClient({
|
|
22
|
+
chain: viemArbitrumSepolia,
|
|
23
|
+
transport: http(),
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const account = privateKeyToAccount(TEST_PRIVATE_KEY);
|
|
27
|
+
walletClient = createWalletClient({
|
|
28
|
+
chain: viemArbitrumSepolia,
|
|
29
|
+
transport: http(),
|
|
30
|
+
account,
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
const config = createCofheConfig({
|
|
36
|
+
supportedChains: [cofheArbSepolia],
|
|
37
|
+
});
|
|
38
|
+
cofheClient = createCofheClient(config);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe('Real TFHE Initialization', () => {
|
|
42
|
+
it('should initialize node-tfhe on first encryption', async () => {
|
|
43
|
+
await cofheClient.connect(publicClient, walletClient);
|
|
44
|
+
|
|
45
|
+
// This will trigger real TFHE initialization
|
|
46
|
+
const encrypted = await cofheClient.encryptInputs([Encryptable.uint128(100n)]).execute();
|
|
47
|
+
|
|
48
|
+
// If we get here, TFHE was initialized successfully
|
|
49
|
+
expect(encrypted).toBeDefined();
|
|
50
|
+
}, 60000); // Longer timeout for real operations
|
|
51
|
+
|
|
52
|
+
it('should handle multiple encryptions without re-initializing', async () => {
|
|
53
|
+
await cofheClient.connect(publicClient, walletClient);
|
|
54
|
+
|
|
55
|
+
// First encryption
|
|
56
|
+
await cofheClient.encryptInputs([Encryptable.uint128(100n)]).execute();
|
|
57
|
+
|
|
58
|
+
// Second encryption should reuse initialization
|
|
59
|
+
await cofheClient.encryptInputs([Encryptable.uint64(50n)]).execute();
|
|
60
|
+
}, 120000);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe('Real Encryption', () => {
|
|
64
|
+
it('should encrypt a bool with real TFHE', async () => {
|
|
65
|
+
await cofheClient.connect(publicClient, walletClient);
|
|
66
|
+
|
|
67
|
+
const encrypted = await cofheClient.encryptInputs([Encryptable.bool(true)]).execute();
|
|
68
|
+
|
|
69
|
+
expect(encrypted.length).toBe(1);
|
|
70
|
+
expect(encrypted[0].utype).toBe(FheTypes.Bool);
|
|
71
|
+
expect(encrypted[0].ctHash).toBeDefined();
|
|
72
|
+
expect(typeof encrypted[0].ctHash).toBe('bigint');
|
|
73
|
+
expect(encrypted[0].signature).toBeDefined();
|
|
74
|
+
expect(typeof encrypted[0].signature).toBe('string');
|
|
75
|
+
expect(encrypted[0].securityZone).toBe(0);
|
|
76
|
+
}, 60000);
|
|
77
|
+
|
|
78
|
+
it('should encrypt all supported types together', async () => {
|
|
79
|
+
await cofheClient.connect(publicClient, walletClient);
|
|
80
|
+
|
|
81
|
+
const inputs = [
|
|
82
|
+
Encryptable.bool(false),
|
|
83
|
+
Encryptable.uint8(1n),
|
|
84
|
+
Encryptable.uint16(2n),
|
|
85
|
+
Encryptable.uint32(3n),
|
|
86
|
+
Encryptable.uint64(4n),
|
|
87
|
+
Encryptable.uint128(5n),
|
|
88
|
+
Encryptable.address('0x742d35Cc6634C0532925a3b844D16faC4c175E99'),
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
const encrypted = await cofheClient.encryptInputs(inputs).execute();
|
|
92
|
+
|
|
93
|
+
expect(encrypted.length).toBe(7);
|
|
94
|
+
// Verify each type
|
|
95
|
+
expect(encrypted[0].utype).toBe(FheTypes.Bool);
|
|
96
|
+
expect(encrypted[1].utype).toBe(FheTypes.Uint8);
|
|
97
|
+
expect(encrypted[2].utype).toBe(FheTypes.Uint16);
|
|
98
|
+
expect(encrypted[3].utype).toBe(FheTypes.Uint32);
|
|
99
|
+
expect(encrypted[4].utype).toBe(FheTypes.Uint64);
|
|
100
|
+
expect(encrypted[5].utype).toBe(FheTypes.Uint128);
|
|
101
|
+
expect(encrypted[6].utype).toBe(FheTypes.Uint160);
|
|
102
|
+
}, 90000); // Longer timeout for multiple encryptions
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe('Real Builder Pattern', () => {
|
|
106
|
+
it('should support chaining builder methods with real encryption', async () => {
|
|
107
|
+
await cofheClient.connect(publicClient, walletClient);
|
|
108
|
+
|
|
109
|
+
const snapshot = cofheClient.getSnapshot();
|
|
110
|
+
const encrypted = await cofheClient
|
|
111
|
+
.encryptInputs([Encryptable.uint128(100n)])
|
|
112
|
+
.setChainId(snapshot.chainId!)
|
|
113
|
+
.setAccount(snapshot.account!)
|
|
114
|
+
.setSecurityZone(0)
|
|
115
|
+
.execute();
|
|
116
|
+
|
|
117
|
+
expect(encrypted.length).toBe(1);
|
|
118
|
+
expect(encrypted[0].utype).toBe(FheTypes.Uint128);
|
|
119
|
+
}, 60000);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
describe('Real Error Handling', () => {
|
|
123
|
+
it('should fail gracefully when not connected', async () => {
|
|
124
|
+
// Don't connect the client
|
|
125
|
+
try {
|
|
126
|
+
await cofheClient.encryptInputs([Encryptable.uint128(100n)]).execute();
|
|
127
|
+
} catch (error) {
|
|
128
|
+
expect(error).toBeInstanceOf(CofheError);
|
|
129
|
+
expect((error as CofheError).code).toBe(CofheErrorCode.NotConnected);
|
|
130
|
+
}
|
|
131
|
+
}, 30000);
|
|
132
|
+
|
|
133
|
+
it('should handle invalid CoFHE URL', async () => {
|
|
134
|
+
const badConfig = createCofheConfig({
|
|
135
|
+
supportedChains: [
|
|
136
|
+
{
|
|
137
|
+
...cofheArbSepolia,
|
|
138
|
+
coFheUrl: 'http://invalid-cofhe-url.local',
|
|
139
|
+
verifierUrl: 'http://invalid-verifier-url.local',
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const badClient = createCofheClient(badConfig);
|
|
145
|
+
await badClient.connect(publicClient, walletClient);
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
await badClient.encryptInputs([Encryptable.uint128(100n)]).execute();
|
|
149
|
+
} catch (error) {
|
|
150
|
+
expect(error).toBeInstanceOf(CofheError);
|
|
151
|
+
expect((error as CofheError).code).toBe(CofheErrorCode.ZkVerifyFailed);
|
|
152
|
+
}
|
|
153
|
+
}, 60000);
|
|
154
|
+
});
|
|
155
|
+
});
|
package/node/index.ts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// Node.js specific functionality only
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
createCofheClientBase,
|
|
5
|
+
createCofheConfigBase,
|
|
6
|
+
type CofheClient,
|
|
7
|
+
type CofheConfig,
|
|
8
|
+
type CofheInputConfig,
|
|
9
|
+
type ZkBuilderAndCrsGenerator,
|
|
10
|
+
type FheKeyDeserializer,
|
|
11
|
+
} from '@/core';
|
|
12
|
+
|
|
13
|
+
// Import node-specific storage (internal use only)
|
|
14
|
+
import { createNodeStorage } from './storage.js';
|
|
15
|
+
|
|
16
|
+
// Import node-tfhe for Node.js
|
|
17
|
+
import { TfheCompactPublicKey, ProvenCompactCiphertextList, CompactPkeCrs, init_panic_hook } from 'node-tfhe';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Internal function to initialize TFHE for Node.js
|
|
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_panic_hook();
|
|
28
|
+
tfheInitialized = true;
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Utility to convert the hex string key to a Uint8Array for use with tfhe
|
|
34
|
+
*/
|
|
35
|
+
const fromHexString = (hexString: string): Uint8Array => {
|
|
36
|
+
const cleanString = hexString.length % 2 === 1 ? `0${hexString}` : hexString;
|
|
37
|
+
const arr = cleanString.replace(/^0x/, '').match(/.{1,2}/g);
|
|
38
|
+
if (!arr) return new Uint8Array();
|
|
39
|
+
return new Uint8Array(arr.map((byte) => parseInt(byte, 16)));
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Serializer for TFHE public keys
|
|
44
|
+
* Validates that the buffer can be deserialized into a TfheCompactPublicKey
|
|
45
|
+
*/
|
|
46
|
+
const tfhePublicKeyDeserializer: FheKeyDeserializer = (buff: string): void => {
|
|
47
|
+
TfheCompactPublicKey.deserialize(fromHexString(buff));
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Serializer for Compact PKE CRS
|
|
52
|
+
* Validates that the buffer can be deserialized into ZkCompactPkePublicParams
|
|
53
|
+
*/
|
|
54
|
+
const compactPkeCrsDeserializer: FheKeyDeserializer = (buff: string): void => {
|
|
55
|
+
CompactPkeCrs.deserialize(fromHexString(buff));
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Creates a ZK builder and CRS from FHE public key and CRS buffers
|
|
60
|
+
* This is used internally by the SDK to create encrypted inputs
|
|
61
|
+
*/
|
|
62
|
+
const zkBuilderAndCrsGenerator: ZkBuilderAndCrsGenerator = (fhe: string, crs: string) => {
|
|
63
|
+
const fhePublicKey = TfheCompactPublicKey.deserialize(fromHexString(fhe));
|
|
64
|
+
const zkBuilder = ProvenCompactCiphertextList.builder(fhePublicKey);
|
|
65
|
+
const zkCrs = CompactPkeCrs.deserialize(fromHexString(crs));
|
|
66
|
+
|
|
67
|
+
return { zkBuilder, zkCrs };
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Creates a CoFHE configuration for Node.js with filesystem storage as default
|
|
72
|
+
* @param config - The CoFHE input configuration (fheKeyStorage will default to filesystem if not provided)
|
|
73
|
+
* @returns The CoFHE configuration with Node.js defaults applied
|
|
74
|
+
*/
|
|
75
|
+
export function createCofheConfig(config: CofheInputConfig): CofheConfig {
|
|
76
|
+
return createCofheConfigBase({
|
|
77
|
+
environment: 'node',
|
|
78
|
+
...config,
|
|
79
|
+
fheKeyStorage: config.fheKeyStorage === null ? null : config.fheKeyStorage ?? createNodeStorage(),
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Creates a CoFHE client instance for Node.js with node-tfhe automatically configured
|
|
85
|
+
* TFHE will be initialized automatically on first encryption - no manual setup required
|
|
86
|
+
* @param config - The CoFHE configuration (use createCofheConfig to create with Node.js defaults)
|
|
87
|
+
* @returns The CoFHE client instance
|
|
88
|
+
*/
|
|
89
|
+
export function createCofheClient(config: CofheConfig): CofheClient {
|
|
90
|
+
return createCofheClientBase({
|
|
91
|
+
config,
|
|
92
|
+
zkBuilderAndCrsGenerator,
|
|
93
|
+
tfhePublicKeyDeserializer,
|
|
94
|
+
compactPkeCrsDeserializer,
|
|
95
|
+
initTfhe,
|
|
96
|
+
});
|
|
97
|
+
}
|
package/node/storage.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/* eslint-disable turbo/no-undeclared-env-vars */
|
|
2
|
+
|
|
3
|
+
import type { IStorage } from '@/core';
|
|
4
|
+
|
|
5
|
+
import { promises as fs } from 'fs';
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
|
|
8
|
+
// Memory storage fallback
|
|
9
|
+
const memoryStorage: Record<string, string> = {};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Creates a node storage implementation using the filesystem
|
|
13
|
+
* @returns IStorage implementation for Node.js environments
|
|
14
|
+
*/
|
|
15
|
+
export const createNodeStorage = (): IStorage => {
|
|
16
|
+
return {
|
|
17
|
+
getItem: async (name: string) => {
|
|
18
|
+
try {
|
|
19
|
+
const storageDir = join(process.env.HOME || process.env.USERPROFILE || '.', '.cofhesdk');
|
|
20
|
+
await fs.mkdir(storageDir, { recursive: true });
|
|
21
|
+
const filePath = join(storageDir, `${name}.json`);
|
|
22
|
+
const data = await fs.readFile(filePath, 'utf8').catch(() => null);
|
|
23
|
+
return data ? JSON.parse(data) : null;
|
|
24
|
+
} catch (e) {
|
|
25
|
+
console.warn('Node.js filesystem modules not available, falling back to memory storage' + e);
|
|
26
|
+
return memoryStorage[name] || null;
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
setItem: async (name: string, value: any) => {
|
|
30
|
+
try {
|
|
31
|
+
const storageDir = join(process.env.HOME || process.env.USERPROFILE || '.', '.cofhesdk');
|
|
32
|
+
await fs.mkdir(storageDir, { recursive: true });
|
|
33
|
+
const filePath = join(storageDir, `${name}.json`);
|
|
34
|
+
await fs.writeFile(filePath, JSON.stringify(value));
|
|
35
|
+
} catch (e) {
|
|
36
|
+
console.warn('Node.js filesystem modules not available, falling back to memory storage' + e);
|
|
37
|
+
memoryStorage[name] = JSON.stringify(value);
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
removeItem: async (name: string) => {
|
|
41
|
+
try {
|
|
42
|
+
const storageDir = join(process.env.HOME || process.env.USERPROFILE || '.', '.cofhesdk');
|
|
43
|
+
const filePath = join(storageDir, `${name}.json`);
|
|
44
|
+
await fs.unlink(filePath).catch(() => {});
|
|
45
|
+
} catch (e) {
|
|
46
|
+
console.warn('Node.js filesystem modules not available, falling back to memory storage' + e);
|
|
47
|
+
delete memoryStorage[name];
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cofhe/sdk",
|
|
3
|
+
"version": "0.0.0-alpha-20260409113701",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "SDK for Fhenix COFHE coprocessor interaction",
|
|
6
|
+
"main": "./dist/core.cjs",
|
|
7
|
+
"module": "./dist/core.js",
|
|
8
|
+
"types": "./dist/core.d.ts",
|
|
9
|
+
"browser": "./dist/web.js",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"import": "./dist/core.js",
|
|
13
|
+
"require": "./dist/core.cjs",
|
|
14
|
+
"types": "./dist/core.d.ts"
|
|
15
|
+
},
|
|
16
|
+
"./adapters": {
|
|
17
|
+
"import": "./dist/adapters.js",
|
|
18
|
+
"require": "./dist/adapters.cjs",
|
|
19
|
+
"types": "./dist/adapters.d.ts"
|
|
20
|
+
},
|
|
21
|
+
"./chains": {
|
|
22
|
+
"import": "./dist/chains.js",
|
|
23
|
+
"require": "./dist/chains.cjs",
|
|
24
|
+
"types": "./dist/chains.d.ts"
|
|
25
|
+
},
|
|
26
|
+
"./permits": {
|
|
27
|
+
"import": "./dist/permits.js",
|
|
28
|
+
"require": "./dist/permits.cjs",
|
|
29
|
+
"types": "./dist/permits.d.ts"
|
|
30
|
+
},
|
|
31
|
+
"./node": {
|
|
32
|
+
"import": "./dist/node.js",
|
|
33
|
+
"require": "./dist/node.cjs",
|
|
34
|
+
"types": "./dist/node.d.ts"
|
|
35
|
+
},
|
|
36
|
+
"./web": {
|
|
37
|
+
"import": "./dist/web.js",
|
|
38
|
+
"require": "./dist/web.cjs",
|
|
39
|
+
"types": "./dist/web.d.ts"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"sideEffects": false,
|
|
43
|
+
"license": "MIT",
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "https://github.com/FhenixProtocol/cofhesdk.git",
|
|
47
|
+
"directory": "packages/sdk"
|
|
48
|
+
},
|
|
49
|
+
"files": [
|
|
50
|
+
"dist/**",
|
|
51
|
+
"core/**",
|
|
52
|
+
"adapters/**",
|
|
53
|
+
"chains/**",
|
|
54
|
+
"permits/**",
|
|
55
|
+
"node/**",
|
|
56
|
+
"web/**",
|
|
57
|
+
"CHANGELOG.md"
|
|
58
|
+
],
|
|
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"
|
|
68
|
+
},
|
|
69
|
+
"peerDependencies": {
|
|
70
|
+
"@nomicfoundation/hardhat-ethers": "^3.0.0",
|
|
71
|
+
"@wagmi/core": "^2.0.0",
|
|
72
|
+
"ethers": "^5.0.0 || ^6.0.0",
|
|
73
|
+
"hardhat": "^2.0.0",
|
|
74
|
+
"viem": "^2.38.6"
|
|
75
|
+
},
|
|
76
|
+
"peerDependenciesMeta": {
|
|
77
|
+
"@wagmi/core": {
|
|
78
|
+
"optional": true
|
|
79
|
+
},
|
|
80
|
+
"ethers": {
|
|
81
|
+
"optional": true
|
|
82
|
+
},
|
|
83
|
+
"hardhat": {
|
|
84
|
+
"optional": true
|
|
85
|
+
},
|
|
86
|
+
"@nomicfoundation/hardhat-ethers": {
|
|
87
|
+
"optional": true
|
|
88
|
+
}
|
|
89
|
+
},
|
|
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",
|
|
102
|
+
"typescript": "5.5.4",
|
|
103
|
+
"vitest": "^3.0.0",
|
|
104
|
+
"@cofhe/eslint-config": "0.2.1",
|
|
105
|
+
"@cofhe/tsconfig": "0.1.2"
|
|
106
|
+
},
|
|
107
|
+
"publishConfig": {
|
|
108
|
+
"access": "public",
|
|
109
|
+
"registry": "https://registry.npmjs.org/"
|
|
110
|
+
},
|
|
111
|
+
"scripts": {
|
|
112
|
+
"build": "tsup",
|
|
113
|
+
"dev": "tsup --watch",
|
|
114
|
+
"lint": "eslint \"**/*.ts*\"",
|
|
115
|
+
"check:types": "tsc --noEmit",
|
|
116
|
+
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist",
|
|
117
|
+
"test": "vitest run",
|
|
118
|
+
"test:watch": "vitest",
|
|
119
|
+
"test:coverage": "vitest run --coverage"
|
|
120
|
+
}
|
|
121
|
+
}
|
package/permits/index.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Core types
|
|
2
|
+
export type {
|
|
3
|
+
Permit,
|
|
4
|
+
CreateSelfPermitOptions as SelfPermitOptions,
|
|
5
|
+
CreateSharingPermitOptions as SharingPermitOptions,
|
|
6
|
+
ImportSharedPermitOptions as ImportPermitOptions,
|
|
7
|
+
SerializedPermit,
|
|
8
|
+
PermitMetadata,
|
|
9
|
+
Permission,
|
|
10
|
+
EIP712Domain,
|
|
11
|
+
EIP712Types,
|
|
12
|
+
EIP712Message,
|
|
13
|
+
ValidationResult,
|
|
14
|
+
PermitSignaturePrimaryType,
|
|
15
|
+
} from './types.js';
|
|
16
|
+
|
|
17
|
+
// Main utilities
|
|
18
|
+
export { PermitUtils } from './permit.js';
|
|
19
|
+
|
|
20
|
+
// Validation utilities
|
|
21
|
+
export {
|
|
22
|
+
// Self permit validators
|
|
23
|
+
SelfPermitOptionsValidator,
|
|
24
|
+
SelfPermitValidator,
|
|
25
|
+
validateSelfPermitOptions,
|
|
26
|
+
validateSelfPermit,
|
|
27
|
+
// Sharing permit validators
|
|
28
|
+
SharingPermitOptionsValidator,
|
|
29
|
+
SharingPermitValidator,
|
|
30
|
+
validateSharingPermitOptions,
|
|
31
|
+
validateSharingPermit,
|
|
32
|
+
// Import permit validators
|
|
33
|
+
ImportPermitOptionsValidator,
|
|
34
|
+
ImportPermitValidator,
|
|
35
|
+
validateImportPermitOptions,
|
|
36
|
+
validateImportPermit,
|
|
37
|
+
// Common utilities
|
|
38
|
+
ValidationUtils,
|
|
39
|
+
} from './validation.js';
|
|
40
|
+
|
|
41
|
+
// Signature utilities
|
|
42
|
+
export { SignatureUtils, getSignatureTypesAndMessage, SignatureTypes } from './signature.js';
|
|
43
|
+
|
|
44
|
+
// Storage utilities
|
|
45
|
+
export {
|
|
46
|
+
permitStore,
|
|
47
|
+
getPermit,
|
|
48
|
+
getActivePermit,
|
|
49
|
+
getPermits,
|
|
50
|
+
setPermit,
|
|
51
|
+
removePermit,
|
|
52
|
+
getActivePermitHash,
|
|
53
|
+
setActivePermitHash,
|
|
54
|
+
removeActivePermitHash,
|
|
55
|
+
clearStaleStore,
|
|
56
|
+
PERMIT_STORE_DEFAULTS,
|
|
57
|
+
} from './store.js';
|
|
58
|
+
|
|
59
|
+
// Sealing utilities
|
|
60
|
+
export { SealingKey, GenerateSealingKey } from './sealing.js';
|
|
61
|
+
export type { EthEncryptedData } from './sealing.js';
|
|
62
|
+
|
|
63
|
+
// Re-export everything for convenience
|
|
64
|
+
export * from './types.js';
|
|
65
|
+
export * from './permit.js';
|
|
66
|
+
export * from './validation.js';
|
|
67
|
+
export * from './signature.js';
|
|
68
|
+
export * from './store.js';
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vitest-environment happy-dom
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
6
|
+
import {
|
|
7
|
+
getPermit,
|
|
8
|
+
setPermit,
|
|
9
|
+
removePermit,
|
|
10
|
+
getActivePermitHash,
|
|
11
|
+
setActivePermitHash,
|
|
12
|
+
PermitUtils,
|
|
13
|
+
permitStore,
|
|
14
|
+
} from './index.js';
|
|
15
|
+
import { createMockPermit } from './test-utils.js';
|
|
16
|
+
|
|
17
|
+
// Type declarations for happy-dom environment
|
|
18
|
+
declare const localStorage: {
|
|
19
|
+
clear: () => void;
|
|
20
|
+
getItem: (name: string) => string | null;
|
|
21
|
+
setItem: (name: string, value: string) => void;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
describe('Permits localStorage Tests', () => {
|
|
25
|
+
const chainId = 1;
|
|
26
|
+
const account = '0x1234567890123456789012345678901234567890';
|
|
27
|
+
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
// Clear localStorage and reset store state
|
|
30
|
+
localStorage.clear();
|
|
31
|
+
permitStore.resetStore();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
afterEach(() => {
|
|
35
|
+
// Clean up after each test
|
|
36
|
+
localStorage.clear();
|
|
37
|
+
permitStore.resetStore();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should persist permits to localStorage', async () => {
|
|
41
|
+
const permit = await createMockPermit();
|
|
42
|
+
|
|
43
|
+
setPermit(chainId, account, permit);
|
|
44
|
+
|
|
45
|
+
// Verify data is stored in localStorage
|
|
46
|
+
const storedData = localStorage.getItem('cofhesdk-permits');
|
|
47
|
+
expect(storedData).toBeDefined();
|
|
48
|
+
|
|
49
|
+
const parsedData = JSON.parse(storedData!);
|
|
50
|
+
expect(parsedData.state.permits[chainId][account][permit.hash]).toBeDefined();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should persist active permit hash to localStorage', async () => {
|
|
54
|
+
const permit = await createMockPermit();
|
|
55
|
+
|
|
56
|
+
setPermit(chainId, account, permit);
|
|
57
|
+
setActivePermitHash(chainId, account, permit.hash);
|
|
58
|
+
|
|
59
|
+
// Verify active permit hash is stored
|
|
60
|
+
const storedData = localStorage.getItem('cofhesdk-permits');
|
|
61
|
+
expect(storedData).toBeDefined();
|
|
62
|
+
|
|
63
|
+
const parsedData = JSON.parse(storedData!);
|
|
64
|
+
expect(parsedData.state.activePermitHash[chainId][account]).toBe(permit.hash);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should restore permits from localStorage', async () => {
|
|
68
|
+
const permit = await createMockPermit();
|
|
69
|
+
|
|
70
|
+
// Add permit to localStorage
|
|
71
|
+
setPermit(chainId, account, permit);
|
|
72
|
+
setActivePermitHash(chainId, account, permit.hash);
|
|
73
|
+
const serializedPermit = PermitUtils.serialize(permit);
|
|
74
|
+
|
|
75
|
+
// Verify data is restored
|
|
76
|
+
const retrievedPermit = getPermit(chainId, account, permit.hash);
|
|
77
|
+
expect(retrievedPermit).toBeDefined();
|
|
78
|
+
expect(PermitUtils.serialize(retrievedPermit!)).toEqual(serializedPermit);
|
|
79
|
+
|
|
80
|
+
const activeHash = getActivePermitHash(chainId, account);
|
|
81
|
+
expect(activeHash).toBe(permit.hash);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should handle corrupted localStorage data gracefully', () => {
|
|
85
|
+
// Set invalid JSON in localStorage
|
|
86
|
+
localStorage.setItem('cofhesdk-permits', 'invalid json');
|
|
87
|
+
|
|
88
|
+
// Store should handle this gracefully
|
|
89
|
+
expect(() => {
|
|
90
|
+
permitStore.store.getState();
|
|
91
|
+
}).not.toThrow();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('should clean up localStorage when permits are removed', async () => {
|
|
95
|
+
const permit = await createMockPermit();
|
|
96
|
+
|
|
97
|
+
setPermit(chainId, account, permit);
|
|
98
|
+
setActivePermitHash(chainId, account, permit.hash);
|
|
99
|
+
|
|
100
|
+
// Verify data exists
|
|
101
|
+
let storedData = localStorage.getItem('cofhesdk-permits');
|
|
102
|
+
expect(storedData).toBeDefined();
|
|
103
|
+
|
|
104
|
+
// Remove permit
|
|
105
|
+
removePermit(chainId, account, permit.hash);
|
|
106
|
+
|
|
107
|
+
// Verify data is cleaned up
|
|
108
|
+
storedData = localStorage.getItem('cofhesdk-permits');
|
|
109
|
+
const parsedData = JSON.parse(storedData!);
|
|
110
|
+
expect(parsedData.state.permits[chainId][account][permit.hash]).toBeUndefined();
|
|
111
|
+
expect(parsedData.state.activePermitHash[chainId][account]).toBeUndefined();
|
|
112
|
+
});
|
|
113
|
+
});
|