@cofhe/sdk 0.1.0 → 0.2.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.
- package/CHANGELOG.md +62 -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 +315 -0
- package/core/client.ts +292 -0
- package/core/clientTypes.ts +108 -0
- package/core/config.test.ts +235 -0
- package/core/config.ts +220 -0
- package/core/decrypt/MockQueryDecrypterAbi.ts +129 -0
- package/core/decrypt/cofheMocksSealOutput.ts +57 -0
- package/core/decrypt/decryptHandleBuilder.ts +287 -0
- package/core/decrypt/decryptUtils.ts +28 -0
- package/core/decrypt/tnSealOutputV1.ts +59 -0
- package/core/decrypt/tnSealOutputV2.ts +298 -0
- package/core/encrypt/MockZkVerifierAbi.ts +106 -0
- package/core/encrypt/cofheMocksZkVerifySign.ts +284 -0
- package/core/encrypt/encryptInputsBuilder.test.ts +751 -0
- package/core/encrypt/encryptInputsBuilder.ts +560 -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 +89 -0
- package/core/keyStore.test.ts +226 -0
- package/core/keyStore.ts +154 -0
- package/core/permits.test.ts +494 -0
- package/core/permits.ts +200 -0
- package/core/types.ts +398 -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 +114 -0
- package/dist/chains.d.cts +121 -0
- package/dist/chains.d.ts +121 -0
- package/dist/chains.js +1 -0
- package/dist/chunk-UGBVZNRT.js +818 -0
- package/dist/chunk-WEAZ25JO.js +105 -0
- package/dist/chunk-WGCRJCBR.js +2523 -0
- package/dist/clientTypes-5_1nwtUe.d.cts +914 -0
- package/dist/clientTypes-Es7fyi65.d.ts +914 -0
- package/dist/core.cjs +3414 -0
- package/dist/core.d.cts +111 -0
- package/dist/core.d.ts +111 -0
- package/dist/core.js +3 -0
- package/dist/node.cjs +3286 -0
- package/dist/node.d.cts +22 -0
- package/dist/node.d.ts +22 -0
- package/dist/node.js +91 -0
- package/dist/permit-fUSe6KKq.d.cts +349 -0
- package/dist/permit-fUSe6KKq.d.ts +349 -0
- package/dist/permits.cjs +871 -0
- package/dist/permits.d.cts +1045 -0
- package/dist/permits.d.ts +1045 -0
- package/dist/permits.js +1 -0
- package/dist/types-KImPrEIe.d.cts +48 -0
- package/dist/types-KImPrEIe.d.ts +48 -0
- package/dist/web.cjs +3478 -0
- package/dist/web.d.cts +38 -0
- package/dist/web.d.ts +38 -0
- package/dist/web.js +240 -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 +147 -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 +27 -15
- package/permits/index.ts +68 -0
- package/permits/localstorage.test.ts +117 -0
- package/permits/permit.test.ts +477 -0
- package/permits/permit.ts +405 -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 +128 -0
- package/permits/store.ts +166 -0
- package/permits/test-utils.ts +20 -0
- package/permits/types.ts +191 -0
- package/permits/utils.ts +62 -0
- package/permits/validation.test.ts +288 -0
- package/permits/validation.ts +369 -0
- package/web/client.web.test.ts +147 -0
- package/web/config.web.test.ts +69 -0
- package/web/encryptInputs.web.test.ts +172 -0
- package/web/index.ts +161 -0
- package/web/storage.ts +34 -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 { createCofhesdkConfig, createCofhesdkClient } from './index.js';
|
|
5
|
+
|
|
6
|
+
describe('@cofhe/node - Config', () => {
|
|
7
|
+
describe('createCofhesdkConfig', () => {
|
|
8
|
+
it('should automatically inject filesystem 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
|
+
const config = createCofhesdkConfig({
|
|
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 = createCofhesdkConfig({
|
|
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 = createCofhesdkConfig({
|
|
43
|
+
supportedChains: [arbSepolia],
|
|
44
|
+
mocks: {
|
|
45
|
+
sealOutputDelay: 0,
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
expect(config.supportedChains).toEqual([arbSepolia]);
|
|
50
|
+
expect(config.mocks.sealOutputDelay).toBe(0);
|
|
51
|
+
expect(config.fheKeyStorage).toBeDefined();
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('createCofhesdkClient with config', () => {
|
|
56
|
+
it('should create client with validated config', () => {
|
|
57
|
+
const config = createCofhesdkConfig({
|
|
58
|
+
supportedChains: [arbSepolia],
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const client = createCofhesdkClient(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 CofhesdkClient, CofhesdkErrorCode, CofhesdkError } from '@/core';
|
|
2
|
+
import { arbSepolia as cofhesdkArbSepolia } 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 { createCofhesdkClient, createCofhesdkConfig } 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 cofhesdkClient: CofhesdkClient;
|
|
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 = createCofhesdkConfig({
|
|
36
|
+
supportedChains: [cofhesdkArbSepolia],
|
|
37
|
+
});
|
|
38
|
+
cofhesdkClient = createCofhesdkClient(config);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe('Real TFHE Initialization', () => {
|
|
42
|
+
it('should initialize node-tfhe on first encryption', async () => {
|
|
43
|
+
await cofhesdkClient.connect(publicClient, walletClient);
|
|
44
|
+
|
|
45
|
+
// This will trigger real TFHE initialization
|
|
46
|
+
const encrypted = await cofhesdkClient.encryptInputs([Encryptable.uint128(100n)]).encrypt();
|
|
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 cofhesdkClient.connect(publicClient, walletClient);
|
|
54
|
+
|
|
55
|
+
// First encryption
|
|
56
|
+
await cofhesdkClient.encryptInputs([Encryptable.uint128(100n)]).encrypt();
|
|
57
|
+
|
|
58
|
+
// Second encryption should reuse initialization
|
|
59
|
+
await cofhesdkClient.encryptInputs([Encryptable.uint64(50n)]).encrypt();
|
|
60
|
+
}, 120000);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe('Real Encryption', () => {
|
|
64
|
+
it('should encrypt a bool with real TFHE', async () => {
|
|
65
|
+
await cofhesdkClient.connect(publicClient, walletClient);
|
|
66
|
+
|
|
67
|
+
const encrypted = await cofhesdkClient.encryptInputs([Encryptable.bool(true)]).encrypt();
|
|
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 cofhesdkClient.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 cofhesdkClient.encryptInputs(inputs).encrypt();
|
|
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 cofhesdkClient.connect(publicClient, walletClient);
|
|
108
|
+
|
|
109
|
+
const snapshot = cofhesdkClient.getSnapshot();
|
|
110
|
+
const encrypted = await cofhesdkClient
|
|
111
|
+
.encryptInputs([Encryptable.uint128(100n)])
|
|
112
|
+
.setChainId(snapshot.chainId!)
|
|
113
|
+
.setAccount(snapshot.account!)
|
|
114
|
+
.setSecurityZone(0)
|
|
115
|
+
.encrypt();
|
|
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 cofhesdkClient.encryptInputs([Encryptable.uint128(100n)]).encrypt();
|
|
127
|
+
} catch (error) {
|
|
128
|
+
expect(error).toBeInstanceOf(CofhesdkError);
|
|
129
|
+
expect((error as CofhesdkError).code).toBe(CofhesdkErrorCode.NotConnected);
|
|
130
|
+
}
|
|
131
|
+
}, 30000);
|
|
132
|
+
|
|
133
|
+
it('should handle invalid CoFHE URL', async () => {
|
|
134
|
+
const badConfig = createCofhesdkConfig({
|
|
135
|
+
supportedChains: [
|
|
136
|
+
{
|
|
137
|
+
...cofhesdkArbSepolia,
|
|
138
|
+
coFheUrl: 'http://invalid-cofhe-url.local',
|
|
139
|
+
verifierUrl: 'http://invalid-verifier-url.local',
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const badClient = createCofhesdkClient(badConfig);
|
|
145
|
+
await badClient.connect(publicClient, walletClient);
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
await badClient.encryptInputs([Encryptable.uint128(100n)]).encrypt();
|
|
149
|
+
} catch (error) {
|
|
150
|
+
expect(error).toBeInstanceOf(CofhesdkError);
|
|
151
|
+
expect((error as CofhesdkError).code).toBe(CofhesdkErrorCode.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
|
+
createCofhesdkClientBase,
|
|
5
|
+
createCofhesdkConfigBase,
|
|
6
|
+
type CofhesdkClient,
|
|
7
|
+
type CofhesdkConfig,
|
|
8
|
+
type CofhesdkInputConfig,
|
|
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 SDK configuration for Node.js with filesystem storage as default
|
|
72
|
+
* @param config - The CoFHE SDK input configuration (fheKeyStorage will default to filesystem if not provided)
|
|
73
|
+
* @returns The CoFHE SDK configuration with Node.js defaults applied
|
|
74
|
+
*/
|
|
75
|
+
export function createCofhesdkConfig(config: CofhesdkInputConfig): CofhesdkConfig {
|
|
76
|
+
return createCofhesdkConfigBase({
|
|
77
|
+
environment: 'node',
|
|
78
|
+
...config,
|
|
79
|
+
fheKeyStorage: config.fheKeyStorage === null ? null : config.fheKeyStorage ?? createNodeStorage(),
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Creates a CoFHE SDK 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 SDK configuration (use createCofhesdkConfig to create with Node.js 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/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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cofhe/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "SDK for Fhenix COFHE coprocessor interaction",
|
|
6
6
|
"main": "./dist/core.cjs",
|
|
@@ -41,25 +41,37 @@
|
|
|
41
41
|
},
|
|
42
42
|
"sideEffects": false,
|
|
43
43
|
"license": "MIT",
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "https://github.com/FhenixProtocol/cofhesdk.git",
|
|
47
|
+
"directory": "packages/sdk"
|
|
48
|
+
},
|
|
44
49
|
"files": [
|
|
45
|
-
"dist/**"
|
|
50
|
+
"dist/**",
|
|
51
|
+
"core/**",
|
|
52
|
+
"adapters/**",
|
|
53
|
+
"chains/**",
|
|
54
|
+
"permits/**",
|
|
55
|
+
"node/**",
|
|
56
|
+
"web/**",
|
|
57
|
+
"CHANGELOG.md"
|
|
46
58
|
],
|
|
47
59
|
"dependencies": {
|
|
60
|
+
"iframe-shared-storage": "^1.0.34",
|
|
48
61
|
"immer": "^10.1.1",
|
|
49
|
-
"zustand": "^5.0.1",
|
|
50
|
-
"zod": "^3.22.0",
|
|
51
|
-
"viem": "^2.0.0",
|
|
52
62
|
"node-tfhe": "0.11.1",
|
|
53
|
-
"idb-keyval": "^6.2.1",
|
|
54
63
|
"tfhe": "0.11.1",
|
|
55
|
-
"tweetnacl": "^1.0.3"
|
|
64
|
+
"tweetnacl": "^1.0.3",
|
|
65
|
+
"viem": "^2.38.6",
|
|
66
|
+
"zod": "^3.22.0",
|
|
67
|
+
"zustand": "^5.0.1"
|
|
56
68
|
},
|
|
57
69
|
"peerDependencies": {
|
|
58
|
-
"
|
|
70
|
+
"@nomicfoundation/hardhat-ethers": "^3.0.0",
|
|
59
71
|
"@wagmi/core": "^2.0.0",
|
|
60
72
|
"ethers": "^5.0.0 || ^6.0.0",
|
|
61
73
|
"hardhat": "^2.0.0",
|
|
62
|
-
"
|
|
74
|
+
"viem": "^2.38.6"
|
|
63
75
|
},
|
|
64
76
|
"peerDependenciesMeta": {
|
|
65
77
|
"@wagmi/core": {
|
|
@@ -76,21 +88,21 @@
|
|
|
76
88
|
}
|
|
77
89
|
},
|
|
78
90
|
"devDependencies": {
|
|
91
|
+
"@nomicfoundation/hardhat-ethers": "^3.0.0",
|
|
79
92
|
"@types/node": "^20.0.0",
|
|
80
93
|
"@vitest/browser": "^3.0.0",
|
|
81
94
|
"@vitest/coverage-v8": "^3.0.0",
|
|
82
95
|
"eslint": "^8.57.0",
|
|
96
|
+
"ethers5": "npm:ethers@^5.7.2",
|
|
97
|
+
"ethers6": "npm:ethers@^6.13.0",
|
|
83
98
|
"happy-dom": "^15.0.0",
|
|
99
|
+
"hardhat": "^2.19.0",
|
|
84
100
|
"playwright": "^1.55.0",
|
|
85
101
|
"tsup": "^8.0.2",
|
|
86
102
|
"typescript": "5.5.4",
|
|
87
103
|
"vitest": "^3.0.0",
|
|
88
|
-
"
|
|
89
|
-
"
|
|
90
|
-
"hardhat": "^2.19.0",
|
|
91
|
-
"@nomicfoundation/hardhat-ethers": "^3.0.0",
|
|
92
|
-
"@cofhe/eslint-config": "0.1.0",
|
|
93
|
-
"@cofhe/tsconfig": "0.1.0"
|
|
104
|
+
"@cofhe/eslint-config": "0.2.0",
|
|
105
|
+
"@cofhe/tsconfig": "0.1.1"
|
|
94
106
|
},
|
|
95
107
|
"publishConfig": {
|
|
96
108
|
"access": "public"
|
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,117 @@
|
|
|
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
|
+
const hash = PermitUtils.getHash(permit);
|
|
43
|
+
|
|
44
|
+
setPermit(chainId, account, permit);
|
|
45
|
+
|
|
46
|
+
// Verify data is stored in localStorage
|
|
47
|
+
const storedData = localStorage.getItem('cofhesdk-permits');
|
|
48
|
+
expect(storedData).toBeDefined();
|
|
49
|
+
|
|
50
|
+
const parsedData = JSON.parse(storedData!);
|
|
51
|
+
expect(parsedData.state.permits[chainId][account][hash]).toBeDefined();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should persist active permit hash to localStorage', async () => {
|
|
55
|
+
const permit = await createMockPermit();
|
|
56
|
+
const hash = PermitUtils.getHash(permit);
|
|
57
|
+
|
|
58
|
+
setPermit(chainId, account, permit);
|
|
59
|
+
setActivePermitHash(chainId, account, hash);
|
|
60
|
+
|
|
61
|
+
// Verify active permit hash is stored
|
|
62
|
+
const storedData = localStorage.getItem('cofhesdk-permits');
|
|
63
|
+
expect(storedData).toBeDefined();
|
|
64
|
+
|
|
65
|
+
const parsedData = JSON.parse(storedData!);
|
|
66
|
+
expect(parsedData.state.activePermitHash[chainId][account]).toBe(hash);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('should restore permits from localStorage', async () => {
|
|
70
|
+
const permit = await createMockPermit();
|
|
71
|
+
const hash = PermitUtils.getHash(permit);
|
|
72
|
+
|
|
73
|
+
// Add permit to localStorage
|
|
74
|
+
setPermit(chainId, account, permit);
|
|
75
|
+
setActivePermitHash(chainId, account, hash);
|
|
76
|
+
const serializedPermit = PermitUtils.serialize(permit);
|
|
77
|
+
|
|
78
|
+
// Verify data is restored
|
|
79
|
+
const retrievedPermit = getPermit(chainId, account, hash);
|
|
80
|
+
expect(retrievedPermit).toBeDefined();
|
|
81
|
+
expect(PermitUtils.serialize(retrievedPermit!)).toEqual(serializedPermit);
|
|
82
|
+
|
|
83
|
+
const activeHash = getActivePermitHash(chainId, account);
|
|
84
|
+
expect(activeHash).toBe(hash);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('should handle corrupted localStorage data gracefully', () => {
|
|
88
|
+
// Set invalid JSON in localStorage
|
|
89
|
+
localStorage.setItem('cofhesdk-permits', 'invalid json');
|
|
90
|
+
|
|
91
|
+
// Store should handle this gracefully
|
|
92
|
+
expect(() => {
|
|
93
|
+
permitStore.store.getState();
|
|
94
|
+
}).not.toThrow();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should clean up localStorage when permits are removed', async () => {
|
|
98
|
+
const permit = await createMockPermit();
|
|
99
|
+
const hash = PermitUtils.getHash(permit);
|
|
100
|
+
|
|
101
|
+
setPermit(chainId, account, permit);
|
|
102
|
+
setActivePermitHash(chainId, account, hash);
|
|
103
|
+
|
|
104
|
+
// Verify data exists
|
|
105
|
+
let storedData = localStorage.getItem('cofhesdk-permits');
|
|
106
|
+
expect(storedData).toBeDefined();
|
|
107
|
+
|
|
108
|
+
// Remove permit
|
|
109
|
+
removePermit(chainId, account, hash, true);
|
|
110
|
+
|
|
111
|
+
// Verify data is cleaned up
|
|
112
|
+
storedData = localStorage.getItem('cofhesdk-permits');
|
|
113
|
+
const parsedData = JSON.parse(storedData!);
|
|
114
|
+
expect(parsedData.state.permits[chainId][account][hash]).toBeUndefined();
|
|
115
|
+
expect(parsedData.state.activePermitHash[chainId][account]).toBeUndefined();
|
|
116
|
+
});
|
|
117
|
+
});
|