@cofhe/sdk 0.3.1 → 0.3.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @cofhe/sdk Changelog
2
2
 
3
+ ## 0.3.2
4
+
5
+ ### Patch Changes
6
+
7
+ - d4e86ea: Aligns with CTA encrypted variables bytes32 representation.
8
+
9
+ - **@cofhe/hardhat-plugin**: `hre.cofhe.mocks.getTestBed()`, `getMockTaskManager()`, `getMockACL()`, `getMockThresholdNetwork()`, and `getMockZkVerifier()` now return typed contracts (typechain interfaces) instead of untyped `Contract`. `getPlaintext(ctHash)` and `expectPlaintext(ctHash, value)` now accept bytes32 ctHashes as `string` support cofhe-contracts 0.1.0 CTA changes.
10
+ - **@cofhe/mock-contracts**: Export typechain-generated contract types (`TestBed`, `MockACL`, `MockTaskManager`, `MockZkVerifier`, `MockThresholdNetwork`) for use with the hardhat plugin. Typechain is run from artifact ABIs only; factory files are not generated.
11
+ - **@cofhe/abi**: CTA-related types use `bytes32` (string) instead of `uint256`. Decryption and return-type helpers aligned with cofhe-contracts 0.1.0.
12
+ - **@cofhe/sdk**: Decryption APIs (`decryptForTx`, `decryptForView`, and related builders) now also accept `string` for ciphertext hashes (bytes32) as well as `bigint`.
13
+
14
+ - 0feaf3f: `cofheClient.decryptForTx` returns a ready-to-use signature
15
+
3
16
  ## 0.3.1
4
17
 
5
18
  ### Patch Changes
@@ -164,6 +164,6 @@ describe('Ethers6Adapter', () => {
164
164
  expect(isInsufficientFunds).toBe(true);
165
165
  console.log('Expected error (insufficient funds or method not supported):', error.message);
166
166
  }
167
- }, 10000);
167
+ }, 20000);
168
168
  });
169
169
  });
package/core/client.ts CHANGED
@@ -146,7 +146,7 @@ export function createCofheClientBase<TConfig extends CofheConfig>(
146
146
  });
147
147
  }
148
148
 
149
- function decryptForView<U extends FheTypes>(ctHash: bigint, utype: U): DecryptForViewBuilder<U> {
149
+ function decryptForView<U extends FheTypes>(ctHash: bigint | string, utype: U): DecryptForViewBuilder<U> {
150
150
  const state = connectStore.getState();
151
151
 
152
152
  return new DecryptForViewBuilder({
@@ -163,7 +163,7 @@ export function createCofheClientBase<TConfig extends CofheConfig>(
163
163
  });
164
164
  }
165
165
 
166
- function decryptForTx(ctHash: bigint): DecryptForTxBuilderUnset {
166
+ function decryptForTx(ctHash: bigint | string): DecryptForTxBuilderUnset {
167
167
  const state = connectStore.getState();
168
168
 
169
169
  return new DecryptForTxBuilder({
@@ -48,9 +48,9 @@ export type CofheClient<TConfig extends CofheConfig = CofheConfig> = {
48
48
  /**
49
49
  * @deprecated Use `decryptForView` instead. Kept for backward compatibility.
50
50
  */
51
- decryptHandle<U extends FheTypes>(ctHash: bigint, utype: U): DecryptForViewBuilder<U>;
52
- decryptForView<U extends FheTypes>(ctHash: bigint, utype: U): DecryptForViewBuilder<U>;
53
- decryptForTx(ctHash: bigint): DecryptForTxBuilderUnset;
51
+ decryptHandle<U extends FheTypes>(ctHash: bigint | string, utype: U): DecryptForViewBuilder<U>;
52
+ decryptForView<U extends FheTypes>(ctHash: bigint | string, utype: U): DecryptForViewBuilder<U>;
53
+ decryptForTx(ctHash: bigint | string): DecryptForTxBuilderUnset;
54
54
  permits: CofheClientPermits;
55
55
  };
56
56
 
@@ -1,8 +1,7 @@
1
1
  import { type Permit, PermitUtils } from '@/permits';
2
2
 
3
- import { encodePacked, keccak256, pad, toHex, type Hex, type PublicClient } from 'viem';
3
+ import { encodePacked, keccak256, type PublicClient } from 'viem';
4
4
  import { sign } from 'viem/accounts';
5
- import { sleep } from '../utils.js';
6
5
  import { MockThresholdNetworkAbi } from './MockThresholdNetworkAbi.js';
7
6
  import { FheTypes } from '../types.js';
8
7
  import { CofheError, CofheErrorCode } from '../error.js';
@@ -10,25 +9,23 @@ import { MOCKS_DECRYPT_RESULT_SIGNER_PRIVATE_KEY } from '../consts.js';
10
9
  import { MOCKS_THRESHOLD_NETWORK_ADDRESS } from '../consts.js';
11
10
 
12
11
  export type DecryptForTxMocksResult = {
13
- ctHash: bigint;
12
+ ctHash: bigint | string;
14
13
  decryptedValue: bigint;
15
- signature: string;
14
+ signature: `0x${string}`;
16
15
  };
17
16
 
18
17
  export async function cofheMocksDecryptForTx(
19
- ctHash: bigint,
18
+ ctHash: bigint | string,
20
19
  utype: FheTypes,
21
20
  permit: Permit | null,
22
- publicClient: PublicClient,
23
- mocksDecryptForTxDelay: number
21
+ publicClient: PublicClient
24
22
  ): Promise<DecryptForTxMocksResult> {
25
- // Configurable delay before decrypting to simulate the CoFHE decrypt processing time
26
- // Recommended 1000ms on web
27
- // Recommended 0ms on hardhat (will be called during tests no need for fake delay)
28
- if (mocksDecryptForTxDelay > 0) await sleep(mocksDecryptForTxDelay);
23
+ let allowed: boolean;
24
+ let error: string;
25
+ let decryptedValue: bigint;
29
26
 
27
+ // With permit
30
28
  if (permit !== null) {
31
- // With permit
32
29
  let permission = PermitUtils.getPermission(permit, true);
33
30
  const permissionWithBigInts = {
34
31
  ...permission,
@@ -36,66 +33,22 @@ export async function cofheMocksDecryptForTx(
36
33
  validatorId: BigInt(permission.validatorId),
37
34
  };
38
35
 
39
- const [allowed, error, result] = await publicClient.readContract({
36
+ [allowed, error, decryptedValue] = await publicClient.readContract({
40
37
  address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
41
38
  abi: MockThresholdNetworkAbi,
42
39
  functionName: 'decryptForTxWithPermit',
43
- args: [ctHash, permissionWithBigInts],
40
+ args: [BigInt(ctHash), permissionWithBigInts],
44
41
  });
45
-
46
- if (error != '') {
47
- throw new CofheError({
48
- code: CofheErrorCode.DecryptFailed,
49
- message: `mocks decryptForTx call failed: ${error}`,
50
- });
51
- }
52
-
53
- if (allowed == false) {
54
- throw new CofheError({
55
- code: CofheErrorCode.DecryptFailed,
56
- message: `mocks decryptForTx call failed: ACL Access Denied (NotAllowed)`,
57
- });
58
- }
59
-
60
- // decryptForTx returns plaintext directly (no sealing/unsealing needed)
61
- // Generate a mock threshold network signature (in production, this would be the actual signature)
62
- // The signature must be valid for MockTaskManager verification.
63
- const chainId = await publicClient.getChainId();
64
- const ctHashBigInt = BigInt(ctHash);
65
- const resultBigInt = BigInt(result);
66
- const encryptionType = Number((ctHashBigInt & (0x7fn << 8n)) >> 8n);
67
-
68
- // Matches Solidity: keccak256(abi.encodePacked(result, uint32(enc_type), uint64(chainId), bytes32(ctHash)))
69
- const ctHashBytes32 = pad(toHex(ctHashBigInt), { size: 32 }) as Hex;
70
- const packed = encodePacked(
71
- ['uint256', 'uint32', 'uint64', 'bytes32'],
72
- [resultBigInt, encryptionType, BigInt(chainId), ctHashBytes32]
73
- );
74
- const messageHash = keccak256(packed);
75
-
76
- // Raw digest signature (no EIP-191 prefix). Must verify against OpenZeppelin ECDSA.recover(messageHash, signature).
77
- const signatureHex = await sign({
78
- hash: messageHash,
79
- privateKey: MOCKS_DECRYPT_RESULT_SIGNER_PRIVATE_KEY,
80
- to: 'hex',
42
+ } else {
43
+ // Without permit (global allowance)
44
+ [allowed, error, decryptedValue] = await publicClient.readContract({
45
+ address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
46
+ abi: MockThresholdNetworkAbi,
47
+ functionName: 'decryptForTxWithoutPermit',
48
+ args: [BigInt(ctHash)],
81
49
  });
82
- const signature = signatureHex.slice(2); // no 0x prefix
83
-
84
- return {
85
- ctHash,
86
- decryptedValue: BigInt(result),
87
- signature,
88
- };
89
50
  }
90
51
 
91
- // Without permit (global allowance)
92
- const [allowed, error, result] = await publicClient.readContract({
93
- address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
94
- abi: MockThresholdNetworkAbi,
95
- functionName: 'decryptForTxWithoutPermit',
96
- args: [ctHash],
97
- });
98
-
99
52
  if (error != '') {
100
53
  throw new CofheError({
101
54
  code: CofheErrorCode.DecryptFailed,
@@ -113,30 +66,19 @@ export async function cofheMocksDecryptForTx(
113
66
  // decryptForTx returns plaintext directly (no sealing/unsealing needed)
114
67
  // Generate a mock threshold network signature (in production, this would be the actual signature)
115
68
  // The signature must be valid for MockTaskManager verification.
116
- const chainId = await publicClient.getChainId();
117
- const ctHashBigInt = BigInt(ctHash);
118
- const resultBigInt = BigInt(result);
119
- const encryptionType = Number((ctHashBigInt & (0x7fn << 8n)) >> 8n);
120
-
121
- // Matches Solidity: keccak256(abi.encodePacked(result, uint32(enc_type), uint64(chainId), bytes32(ctHash)))
122
- const ctHashBytes32 = pad(toHex(ctHashBigInt), { size: 32 }) as Hex;
123
- const packed = encodePacked(
124
- ['uint256', 'uint32', 'uint64', 'bytes32'],
125
- [resultBigInt, encryptionType, BigInt(chainId), ctHashBytes32]
126
- );
69
+ const packed = encodePacked(['uint256', 'uint256'], [BigInt(ctHash), decryptedValue]);
127
70
  const messageHash = keccak256(packed);
128
71
 
129
72
  // Raw digest signature (no EIP-191 prefix). Must verify against OpenZeppelin ECDSA.recover(messageHash, signature).
130
- const signatureHex = await sign({
73
+ const signature = await sign({
131
74
  hash: messageHash,
132
75
  privateKey: MOCKS_DECRYPT_RESULT_SIGNER_PRIVATE_KEY,
133
76
  to: 'hex',
134
77
  });
135
- const signature = signatureHex.slice(2); // no 0x prefix
136
78
 
137
79
  return {
138
80
  ctHash,
139
- decryptedValue: BigInt(result),
81
+ decryptedValue,
140
82
  signature,
141
83
  };
142
84
  }
@@ -1,24 +1,17 @@
1
1
  import { type Permit, PermitUtils } from '@/permits';
2
2
 
3
3
  import { type PublicClient } from 'viem';
4
- import { sleep } from '../utils.js';
5
4
  import { MockThresholdNetworkAbi } from './MockThresholdNetworkAbi.js';
6
5
  import { FheTypes } from '../types.js';
7
6
  import { CofheError, CofheErrorCode } from '../error.js';
8
7
  import { MOCKS_THRESHOLD_NETWORK_ADDRESS } from '../consts.js';
9
8
 
10
9
  export async function cofheMocksDecryptForView(
11
- ctHash: bigint,
10
+ ctHash: bigint | string,
12
11
  utype: FheTypes,
13
12
  permit: Permit,
14
- publicClient: PublicClient,
15
- mocksDecryptDelay: number
13
+ publicClient: PublicClient
16
14
  ): Promise<bigint> {
17
- // Configurable delay before decrypting the output to simulate the CoFHE decrypt processing time
18
- // Recommended 1000ms on web
19
- // Recommended 0ms on hardhat (will be called during tests no need for fake delay)
20
- if (mocksDecryptDelay > 0) await sleep(mocksDecryptDelay);
21
-
22
15
  const permission = PermitUtils.getPermission(permit, true);
23
16
  const permissionWithBigInts = {
24
17
  ...permission,
@@ -30,7 +23,7 @@ export async function cofheMocksDecryptForView(
30
23
  address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
31
24
  abi: MockThresholdNetworkAbi,
32
25
  functionName: 'querySealOutput',
33
- args: [ctHash, BigInt(utype), permissionWithBigInts],
26
+ args: [BigInt(ctHash), BigInt(utype), permissionWithBigInts],
34
27
  });
35
28
 
36
29
  if (error != '') {
@@ -8,7 +8,7 @@ import { CofheError, CofheErrorCode } from '../error.js';
8
8
  import { permits } from '../permits.js';
9
9
  import { BaseBuilder, type BaseBuilderParams } from '../baseBuilder.js';
10
10
  import { cofheMocksDecryptForTx } from './cofheMocksDecryptForTx.js';
11
- import { getPublicClientChainID } from '../utils.js';
11
+ import { getPublicClientChainID, sleep } from '../utils.js';
12
12
  import { tnDecrypt } from './tnDecrypt.js';
13
13
 
14
14
  /**
@@ -36,13 +36,13 @@ import { tnDecrypt } from './tnDecrypt.js';
36
36
  type DecryptForTxPermitSelection = 'unset' | 'with-permit' | 'without-permit';
37
37
 
38
38
  type DecryptForTxBuilderParams = BaseBuilderParams & {
39
- ctHash: bigint;
39
+ ctHash: bigint | string;
40
40
  };
41
41
 
42
42
  export type DecryptForTxResult = {
43
- ctHash: bigint;
43
+ ctHash: bigint | string;
44
44
  decryptedValue: bigint;
45
- signature: string; // Threshold network signature for publishDecryptResult
45
+ signature: `0x${string}`; // Threshold network signature for publishDecryptResult
46
46
  };
47
47
 
48
48
  /**
@@ -56,7 +56,7 @@ export type DecryptForTxBuilderUnset = Omit<DecryptForTxBuilder, 'execute'>;
56
56
  export type DecryptForTxBuilderSelected = Omit<DecryptForTxBuilder, 'withPermit' | 'withoutPermit'>;
57
57
 
58
58
  export class DecryptForTxBuilder extends BaseBuilder {
59
- private ctHash: bigint;
59
+ private ctHash: bigint | string;
60
60
  private permitHash?: string;
61
61
  private permit?: Permit;
62
62
  private permitSelection: DecryptForTxPermitSelection = 'unset';
@@ -271,8 +271,13 @@ export class DecryptForTxBuilder extends BaseBuilder {
271
271
  private async mocksDecryptForTx(permit: Permit | null): Promise<DecryptForTxResult> {
272
272
  this.assertPublicClient();
273
273
 
274
+ // Configurable delay before decrypting to simulate the CoFHE decrypt processing time
275
+ // Recommended 1000ms on web
276
+ // Recommended 0ms on hardhat (will be called during tests no need for fake delay)
274
277
  const delay = this.config.mocks.decryptDelay;
275
- const result = await cofheMocksDecryptForTx(this.ctHash, 0 as FheTypes, permit, this.publicClient, delay);
278
+ if (delay > 0) await sleep(delay);
279
+
280
+ const result = await cofheMocksDecryptForTx(this.ctHash, 0 as FheTypes, permit, this.publicClient);
276
281
  return result;
277
282
  }
278
283
 
@@ -11,7 +11,7 @@ import { BaseBuilder, type BaseBuilderParams } from '../baseBuilder.js';
11
11
  import { cofheMocksDecryptForView } from './cofheMocksDecryptForView.js';
12
12
  // import { tnSealOutputV1 } from './tnSealOutputV1.js';
13
13
  import { tnSealOutputV2 } from './tnSealOutputV2.js';
14
- import { cofheMocksDecryptForTx } from './cofheMocksDecryptForTx.js';
14
+ import { sleep } from '../utils.js';
15
15
 
16
16
  /**
17
17
  * API
@@ -35,14 +35,14 @@ import { cofheMocksDecryptForTx } from './cofheMocksDecryptForTx.js';
35
35
  */
36
36
 
37
37
  type DecryptForViewBuilderParams<U extends FheTypes> = BaseBuilderParams & {
38
- ctHash: bigint;
38
+ ctHash: bigint | string;
39
39
  utype: U;
40
40
  permitHash?: string;
41
41
  permit?: Permit;
42
42
  };
43
43
 
44
44
  export class DecryptForViewBuilder<U extends FheTypes> extends BaseBuilder {
45
- private ctHash: bigint;
45
+ private ctHash: bigint | string;
46
46
  private utype: U;
47
47
  private permitHash?: string;
48
48
  private permit?: Permit;
@@ -245,8 +245,13 @@ export class DecryptForViewBuilder<U extends FheTypes> extends BaseBuilder {
245
245
  private async mocksSealOutput(permit: Permit): Promise<bigint> {
246
246
  this.assertPublicClient();
247
247
 
248
+ // Configurable delay before decrypting the output to simulate the CoFHE decrypt processing time
249
+ // Recommended 1000ms on web
250
+ // Recommended 0ms on hardhat (will be called during tests no need for fake delay)
248
251
  const mocksDecryptDelay = this.config.mocks.decryptDelay;
249
- return cofheMocksDecryptForView(this.ctHash, this.utype, permit, this.publicClient, mocksDecryptDelay);
252
+ if (mocksDecryptDelay > 0) await sleep(mocksDecryptDelay);
253
+
254
+ return cofheMocksDecryptForView(this.ctHash, this.utype, permit, this.publicClient);
250
255
  }
251
256
 
252
257
  /**
@@ -1,6 +1,7 @@
1
1
  import { type Permission } from '@/permits';
2
2
 
3
3
  import { CofheError, CofheErrorCode } from '../error.js';
4
+ import { parseSignature, serializeSignature } from 'viem';
4
5
 
5
6
  type TnDecryptResponse = {
6
7
  // TN returns bytes in big-endian order, e.g. [0,0,0,42]
@@ -10,7 +11,7 @@ type TnDecryptResponse = {
10
11
  error_message: string | null;
11
12
  };
12
13
 
13
- function normalizeSignature(signature: unknown): string {
14
+ function normalizeSignature(signature: unknown): `0x${string}` {
14
15
  if (typeof signature !== 'string') {
15
16
  throw new CofheError({
16
17
  code: CofheErrorCode.DecryptReturnedNull,
@@ -29,8 +30,9 @@ function normalizeSignature(signature: unknown): string {
29
30
  });
30
31
  }
31
32
 
32
- // SDK uses "no-0x" signatures in mocks/tests; normalize to that format.
33
- return trimmed.startsWith('0x') ? trimmed.slice(2) : trimmed;
33
+ const prefixed = trimmed.startsWith('0x') ? (trimmed as `0x${string}`) : (`0x${trimmed}` as `0x${string}`);
34
+ const parsed = parseSignature(prefixed);
35
+ return serializeSignature(parsed);
34
36
  }
35
37
 
36
38
  function parseDecryptedBytesToBigInt(decrypted: unknown): bigint {
@@ -127,17 +129,17 @@ function assertTnDecryptResponse(value: unknown): TnDecryptResponse {
127
129
  }
128
130
 
129
131
  export async function tnDecrypt(
130
- ctHash: bigint,
132
+ ctHash: bigint | string,
131
133
  chainId: number,
132
134
  permission: Permission | null,
133
135
  thresholdNetworkUrl: string
134
- ): Promise<{ decryptedValue: bigint; signature: string }> {
136
+ ): Promise<{ decryptedValue: bigint; signature: `0x${string}` }> {
135
137
  const body: {
136
138
  ct_tempkey: string;
137
139
  host_chain_id: number;
138
140
  permit?: Permission;
139
141
  } = {
140
- ct_tempkey: ctHash.toString(16).padStart(64, '0'),
142
+ ct_tempkey: BigInt(ctHash).toString(16).padStart(64, '0'),
141
143
  host_chain_id: chainId,
142
144
  };
143
145
 
@@ -57,12 +57,12 @@ function convertSealedData(sealed: SealOutputStatusResponse['sealed']): EthEncry
57
57
  */
58
58
  async function submitSealOutputRequest(
59
59
  thresholdNetworkUrl: string,
60
- ctHash: bigint,
60
+ ctHash: bigint | string,
61
61
  chainId: number,
62
62
  permission: Permission
63
63
  ): Promise<string> {
64
64
  const body = {
65
- ct_tempkey: ctHash.toString(16).padStart(64, '0'),
65
+ ct_tempkey: BigInt(ctHash).toString(16).padStart(64, '0'),
66
66
  host_chain_id: chainId,
67
67
  permit: permission,
68
68
  };
@@ -285,7 +285,7 @@ async function pollSealOutputStatus(thresholdNetworkUrl: string, requestId: stri
285
285
  }
286
286
 
287
287
  export async function tnSealOutputV2(
288
- ctHash: bigint,
288
+ ctHash: bigint | string,
289
289
  chainId: number,
290
290
  permission: Permission,
291
291
  thresholdNetworkUrl: string
@@ -13,7 +13,7 @@ import {
13
13
  import { MockZkVerifierAbi } from './MockZkVerifierAbi.js';
14
14
  import { hardhat } from 'viem/chains';
15
15
  import { CofheError, CofheErrorCode } from '../error.js';
16
- import { privateKeyToAccount } from 'viem/accounts';
16
+ import { privateKeyToAccount, sign } from 'viem/accounts';
17
17
  import { MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY, MOCKS_ZK_VERIFIER_ADDRESS } from '../consts.js';
18
18
 
19
19
  type EncryptableItemWithCtHash = EncryptableItem & {
@@ -181,7 +181,11 @@ async function insertCtHashes(items: EncryptableItemWithCtHash[], walletClient:
181
181
  * The mocks verify the EncryptedInputs' signature against the known proof signer account.
182
182
  * Locally, we create the proof signatures from the known proof signer account.
183
183
  */
184
- async function createProofSignatures(items: EncryptableItemWithCtHash[], securityZone: number): Promise<string[]> {
184
+ async function createProofSignatures(
185
+ items: EncryptableItemWithCtHash[],
186
+ securityZone: number,
187
+ account: string
188
+ ): Promise<string[]> {
185
189
  let signatures: string[] = [];
186
190
 
187
191
  // Create wallet client for the encrypted input signer
@@ -205,16 +209,16 @@ async function createProofSignatures(items: EncryptableItemWithCtHash[], securit
205
209
  try {
206
210
  for (const item of items) {
207
211
  // Pack the data into bytes and hash it
208
- const packedData = encodePacked(['uint256', 'int32', 'uint8'], [BigInt(item.data), securityZone, item.utype]);
212
+ const packedData = encodePacked(
213
+ ['uint256', 'uint8', 'uint8', 'address', 'uint256'],
214
+ [BigInt(item.ctHash), item.utype, securityZone, account as `0x${string}`, BigInt(hardhat.id)]
215
+ );
209
216
  const messageHash = keccak256(packedData);
210
217
 
211
- // Convert to EthSignedMessageHash (adds "\x19Ethereum Signed Message:\n32" prefix)
212
- const ethSignedHash = hashMessage({ raw: toBytes(messageHash) });
213
-
214
- // Sign the message
215
- const signature = await encInputSignerClient.signMessage({
216
- message: { raw: toBytes(ethSignedHash) },
217
- account: encInputSignerClient.account!,
218
+ const signature = await sign({
219
+ hash: messageHash,
220
+ privateKey: MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY,
221
+ to: 'hex',
218
222
  });
219
223
 
220
224
  signatures.push(signature);
@@ -267,7 +271,7 @@ export async function cofheMocksZkVerifySign(
267
271
  await insertCtHashes(encryptableItems, _walletClient);
268
272
 
269
273
  // Locally create the proof signatures from the known proof signer account
270
- const signatures = await createProofSignatures(encryptableItems, securityZone);
274
+ const signatures = await createProofSignatures(encryptableItems, securityZone, account);
271
275
 
272
276
  // Return the ctHashes and signatures in the same format as CoFHE
273
277
  return encryptableItems.map((item, index) => ({