@zama-fhe/relayer-sdk 0.1.0 → 0.1.1

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/lib/node.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as TFHEPkg from 'node-tfhe';
2
2
  import { ShortintParameters, ShortintParametersName, ShortintCompactPublicKeyEncryptionParameters, ShortintCompactPublicKeyEncryptionParametersName, TfheConfigBuilder, TfheClientKey, TfheCompactPublicKey, CompactPkeCrs } from 'node-tfhe';
3
3
  import * as TKMSPkg from 'node-tkms';
4
- import { JsonRpcProvider, BrowserProvider, Contract, ethers, getAddress, isAddress, AbiCoder } from 'ethers';
4
+ import { JsonRpcProvider, BrowserProvider, Contract, ethers, getAddress as getAddress$2, isAddress, AbiCoder } from 'ethers';
5
5
  import createHash from 'keccak';
6
6
  import fetchRetry from 'fetch-retry';
7
7
 
@@ -23,7 +23,9 @@ const fromHexString = (hexString) => {
23
23
  return new Uint8Array();
24
24
  return Uint8Array.from(arr.map((byte) => parseInt(byte, 16)));
25
25
  };
26
- const toHexString = (bytes, with0x = false) => `${with0x ? '0x' : ''}${bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '')}`;
26
+ function toHexString(bytes, with0x = false) {
27
+ return `${with0x ? '0x' : ''}${bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '')}`;
28
+ }
27
29
  const bytesToBigInt = function (byteArray) {
28
30
  if (!byteArray || byteArray?.length === 0) {
29
31
  return BigInt(0);
@@ -34,95 +36,370 @@ const bytesToBigInt = function (byteArray) {
34
36
  return BigInt(`0x${hex}`);
35
37
  };
36
38
 
37
- const keyurlCache = {};
38
- const getKeysFromRelayer = async (url, publicKeyId) => {
39
- if (keyurlCache[url]) {
40
- return keyurlCache[url];
39
+ function getErrorCause(e) {
40
+ if (e instanceof Error && typeof e.cause === 'object' && e.cause !== null) {
41
+ return e.cause;
41
42
  }
42
- try {
43
- const response = await fetch(`${url}/v1/keyurl`);
44
- if (!response.ok) {
45
- throw new Error(`HTTP error! status: ${response.status}`);
46
- }
47
- const data = await response.json();
48
- if (data) {
49
- let pubKeyUrl;
50
- // If no publicKeyId is provided, use the first one
51
- // Warning: if there are multiple keys available, the first one will most likely never be the
52
- // same between several calls (fetching the infos is non-deterministic)
53
- if (!publicKeyId) {
54
- pubKeyUrl = data.response.fhe_key_info[0].fhe_public_key.urls[0];
55
- publicKeyId = data.response.fhe_key_info[0].fhe_public_key.data_id;
56
- }
57
- else {
58
- // If a publicKeyId is provided, get the corresponding info
59
- const keyInfo = data.response.fhe_key_info.find((info) => info.fhe_public_key.data_id === publicKeyId);
60
- if (!keyInfo) {
61
- throw new Error(`Could not find FHE key info with data_id ${publicKeyId}`);
62
- }
63
- // TODO: Get a given party's public key url instead of the first one
64
- pubKeyUrl = keyInfo.fhe_public_key.urls[0];
65
- }
66
- const publicKeyResponse = await fetch(pubKeyUrl);
67
- if (!publicKeyResponse.ok) {
68
- throw new Error(`HTTP error! status: ${publicKeyResponse.status} on ${publicKeyResponse.url}`);
69
- }
70
- let publicKey;
71
- if (typeof publicKeyResponse.bytes === 'function') {
72
- // bytes is not widely supported yet
73
- publicKey = await publicKeyResponse.bytes();
74
- }
75
- else {
76
- publicKey = new Uint8Array(await publicKeyResponse.arrayBuffer());
43
+ return undefined;
44
+ }
45
+ function getErrorCauseCode(e) {
46
+ const cause = getErrorCause(e);
47
+ if (!cause || !('code' in cause) || !cause.code) {
48
+ return undefined;
49
+ }
50
+ if (typeof cause.code !== 'string') {
51
+ return undefined;
52
+ }
53
+ return cause.code;
54
+ }
55
+ function getErrorCauseStatus(e) {
56
+ const cause = getErrorCause(e);
57
+ if (!cause || !('status' in cause) || cause.status === undefined) {
58
+ return undefined;
59
+ }
60
+ if (typeof cause.status !== 'number') {
61
+ return undefined;
62
+ }
63
+ return cause.status;
64
+ }
65
+ async function throwRelayerResponseError(operation, response) {
66
+ let message;
67
+ // Special case for 429
68
+ if (response.status === 429) {
69
+ message = `Relayer rate limit exceeded: Please wait and try again later.`;
70
+ }
71
+ else {
72
+ switch (operation) {
73
+ case 'PUBLIC_DECRYPT': {
74
+ message = `Public decrypt failed: relayer respond with HTTP code ${response.status}`;
75
+ break;
77
76
  }
78
- const publicParamsUrl = data.response.crs['2048'].urls[0];
79
- const publicParamsId = data.response.crs['2048'].data_id;
80
- const publicParams2048Response = await fetch(publicParamsUrl);
81
- if (!publicParams2048Response.ok) {
82
- throw new Error(`HTTP error! status: ${publicParams2048Response.status} on ${publicParams2048Response.url}`);
77
+ case 'USER_DECRYPT': {
78
+ message = `User decrypt failed: relayer respond with HTTP code ${response.status}`;
79
+ break;
83
80
  }
84
- let publicParams2048;
85
- if (typeof publicParams2048Response.bytes === 'function') {
86
- // bytes is not widely supported yet
87
- publicParams2048 = await publicParams2048Response.bytes();
81
+ case 'KEY_URL': {
82
+ message = `HTTP error! status: ${response.status}`;
83
+ break;
88
84
  }
89
- else {
90
- publicParams2048 = new Uint8Array(await publicParams2048Response.arrayBuffer());
85
+ default: {
86
+ const responseText = await response.text();
87
+ message = `Relayer didn't response correctly. Bad status ${response.statusText}. Content: ${responseText}`;
88
+ break;
91
89
  }
92
- let pub_key;
93
- try {
94
- pub_key = TFHE.TfheCompactPublicKey.safe_deserialize(publicKey, SERIALIZED_SIZE_LIMIT_PK);
90
+ }
91
+ }
92
+ const cause = {
93
+ code: 'RELAYER_FETCH_ERROR',
94
+ operation,
95
+ status: response.status,
96
+ statusText: response.statusText,
97
+ url: response.url,
98
+ };
99
+ throw new Error(message, {
100
+ cause,
101
+ });
102
+ }
103
+ function throwRelayerJSONError(operation, error) {
104
+ let message;
105
+ switch (operation) {
106
+ case 'PUBLIC_DECRYPT': {
107
+ message = "Public decrypt failed: Relayer didn't return a JSON";
108
+ break;
109
+ }
110
+ case 'USER_DECRYPT': {
111
+ message = "User decrypt failed: Relayer didn't return a JSON";
112
+ break;
113
+ }
114
+ default: {
115
+ message = "Relayer didn't return a JSON";
116
+ break;
117
+ }
118
+ }
119
+ const cause = {
120
+ code: 'RELAYER_NO_JSON_ERROR',
121
+ operation,
122
+ error,
123
+ };
124
+ throw new Error(message, {
125
+ cause,
126
+ });
127
+ }
128
+ function throwRelayerUnexpectedJSONError(operation, error) {
129
+ let message;
130
+ switch (operation) {
131
+ case 'PUBLIC_DECRYPT': {
132
+ message =
133
+ 'Public decrypt failed: Relayer returned an unexpected JSON response';
134
+ break;
135
+ }
136
+ case 'USER_DECRYPT': {
137
+ message =
138
+ 'User decrypt failed: Relayer returned an unexpected JSON response';
139
+ break;
140
+ }
141
+ default: {
142
+ message = 'Relayer returned an unexpected JSON response';
143
+ break;
144
+ }
145
+ }
146
+ const cause = {
147
+ code: 'RELAYER_UNEXPECTED_JSON_ERROR',
148
+ operation,
149
+ error,
150
+ };
151
+ throw new Error(message, {
152
+ cause,
153
+ });
154
+ }
155
+ function throwRelayerInternalError(operation, json) {
156
+ let message;
157
+ switch (operation) {
158
+ case 'PUBLIC_DECRYPT': {
159
+ message =
160
+ "Pulbic decrypt failed: the public decryption didn't succeed for an unknown reason";
161
+ break;
162
+ }
163
+ case 'USER_DECRYPT': {
164
+ message =
165
+ "User decrypt failed: the user decryption didn't succeed for an unknown reason";
166
+ break;
167
+ }
168
+ default: {
169
+ message = "Relayer didn't response correctly.";
170
+ break;
171
+ }
172
+ }
173
+ const cause = {
174
+ code: 'RELAYER_INTERNAL_ERROR',
175
+ operation,
176
+ error: json,
177
+ };
178
+ throw new Error(message, {
179
+ cause,
180
+ });
181
+ }
182
+ function throwRelayerUnknownError(operation, error, message) {
183
+ if (!message) {
184
+ switch (operation) {
185
+ case 'PUBLIC_DECRYPT': {
186
+ message = "Public decrypt failed: Relayer didn't respond";
187
+ break;
95
188
  }
96
- catch (e) {
97
- throw new Error('Invalid public key (deserialization failed)', {
98
- cause: e,
99
- });
189
+ case 'USER_DECRYPT': {
190
+ message = "User decrypt failed: Relayer didn't respond";
191
+ break;
100
192
  }
101
- let crs;
102
- try {
103
- crs = TFHE.CompactPkeCrs.safe_deserialize(new Uint8Array(publicParams2048), SERIALIZED_SIZE_LIMIT_CRS);
193
+ default: {
194
+ message = "Relayer didn't response correctly. Bad JSON.";
195
+ break;
104
196
  }
105
- catch (e) {
106
- throw new Error('Invalid crs (deserialization failed)', {
107
- cause: e,
108
- });
197
+ }
198
+ }
199
+ const cause = {
200
+ code: 'RELAYER_UNKNOWN_ERROR',
201
+ operation,
202
+ error,
203
+ };
204
+ throw new Error(message ?? "Relayer didn't response correctly.", {
205
+ cause,
206
+ });
207
+ }
208
+
209
+ function assertIsRelayerFetchResponseJson(json) {
210
+ if (!json || typeof json !== 'object') {
211
+ throw new Error('Unexpected response JSON.');
212
+ }
213
+ if (!('response' in json &&
214
+ json.response !== null &&
215
+ json.response !== undefined)) {
216
+ throw new Error("Unexpected response JSON format: missing 'response' property.");
217
+ }
218
+ }
219
+ async function fetchRelayerJsonRpcPost(relayerOperation, url, payload, options) {
220
+ const init = {
221
+ method: 'POST',
222
+ headers: {
223
+ 'Content-Type': 'application/json',
224
+ ...(options?.apiKey && { 'x-api-key': options.apiKey }),
225
+ },
226
+ body: JSON.stringify(payload),
227
+ };
228
+ let response;
229
+ let json;
230
+ try {
231
+ response = await fetch(url, init);
232
+ }
233
+ catch (e) {
234
+ throwRelayerUnknownError(relayerOperation, e);
235
+ }
236
+ if (!response.ok) {
237
+ await throwRelayerResponseError(relayerOperation, response);
238
+ }
239
+ let parsed;
240
+ try {
241
+ parsed = await response.json();
242
+ }
243
+ catch (e) {
244
+ throwRelayerJSONError(relayerOperation, e);
245
+ }
246
+ try {
247
+ assertIsRelayerFetchResponseJson(parsed);
248
+ json = parsed;
249
+ }
250
+ catch (e) {
251
+ throwRelayerUnexpectedJSONError(relayerOperation, e);
252
+ }
253
+ return json;
254
+ }
255
+ async function fetchRelayerGet(relayerOperation, url) {
256
+ let response;
257
+ let json;
258
+ try {
259
+ response = await fetch(url);
260
+ }
261
+ catch (e) {
262
+ throwRelayerUnknownError(relayerOperation, e);
263
+ }
264
+ if (!response.ok) {
265
+ await throwRelayerResponseError(relayerOperation, response);
266
+ }
267
+ let parsed;
268
+ try {
269
+ parsed = await response.json();
270
+ }
271
+ catch (e) {
272
+ throwRelayerJSONError(relayerOperation, e);
273
+ }
274
+ try {
275
+ assertIsRelayerFetchResponseJson(parsed);
276
+ json = parsed;
277
+ }
278
+ catch (e) {
279
+ throwRelayerUnexpectedJSONError(relayerOperation, e);
280
+ }
281
+ return json;
282
+ }
283
+
284
+ // export type RelayerKeysItem = {
285
+ // data_id: string;
286
+ // param_choice: number;
287
+ // urls: string[];
288
+ // signatures: string[];
289
+ // };
290
+ // export type RelayerKey = {
291
+ // data_id: string;
292
+ // param_choice: number;
293
+ // signatures: string[];
294
+ // urls: string[];
295
+ // };
296
+ // export type RelayerKeys = {
297
+ // response: {
298
+ // fhe_key_info: {
299
+ // fhe_public_key: RelayerKey;
300
+ // fhe_server_key: RelayerKey;
301
+ // }[];
302
+ // verf_public_key: {
303
+ // key_id: string;
304
+ // server_id: number;
305
+ // verf_public_key_address: string;
306
+ // verf_public_key_url: string;
307
+ // }[];
308
+ // crs: {
309
+ // [key: string]: RelayerKeysItem;
310
+ // };
311
+ // };
312
+ // status: string;
313
+ // };
314
+ const keyurlCache = {};
315
+ const getKeysFromRelayer = async (url, publicKeyId) => {
316
+ if (keyurlCache[url]) {
317
+ return keyurlCache[url];
318
+ }
319
+ const data = await fetchRelayerGet('KEY_URL', `${url}/v1/keyurl`);
320
+ try {
321
+ // const response = await fetch(`${url}/v1/keyurl`);
322
+ // if (!response.ok) {
323
+ // await throwRelayerResponseError("KEY_URL", response);
324
+ // }
325
+ //const data: RelayerKeys = await response.json();
326
+ //if (data) {
327
+ let pubKeyUrl;
328
+ // If no publicKeyId is provided, use the first one
329
+ // Warning: if there are multiple keys available, the first one will most likely never be the
330
+ // same between several calls (fetching the infos is non-deterministic)
331
+ if (!publicKeyId) {
332
+ pubKeyUrl = data.response.fhe_key_info[0].fhe_public_key.urls[0];
333
+ publicKeyId = data.response.fhe_key_info[0].fhe_public_key.data_id;
334
+ }
335
+ else {
336
+ // If a publicKeyId is provided, get the corresponding info
337
+ const keyInfo = data.response.fhe_key_info.find((info) => info.fhe_public_key.data_id === publicKeyId);
338
+ if (!keyInfo) {
339
+ throw new Error(`Could not find FHE key info with data_id ${publicKeyId}`);
109
340
  }
110
- const result = {
111
- publicKey: pub_key,
112
- publicKeyId,
113
- publicParams: {
114
- 2048: {
115
- publicParams: crs,
116
- publicParamsId,
117
- },
118
- },
119
- };
120
- keyurlCache[url] = result;
121
- return result;
341
+ // TODO: Get a given party's public key url instead of the first one
342
+ pubKeyUrl = keyInfo.fhe_public_key.urls[0];
343
+ }
344
+ const publicKeyResponse = await fetch(pubKeyUrl);
345
+ if (!publicKeyResponse.ok) {
346
+ throw new Error(`HTTP error! status: ${publicKeyResponse.status} on ${publicKeyResponse.url}`);
347
+ }
348
+ let publicKey;
349
+ if (typeof publicKeyResponse.bytes === 'function') {
350
+ // bytes is not widely supported yet
351
+ publicKey = await publicKeyResponse.bytes();
122
352
  }
123
353
  else {
124
- throw new Error('No public key available');
354
+ publicKey = new Uint8Array(await publicKeyResponse.arrayBuffer());
355
+ }
356
+ const publicParamsUrl = data.response.crs['2048'].urls[0];
357
+ const publicParamsId = data.response.crs['2048'].data_id;
358
+ const publicParams2048Response = await fetch(publicParamsUrl);
359
+ if (!publicParams2048Response.ok) {
360
+ throw new Error(`HTTP error! status: ${publicParams2048Response.status} on ${publicParams2048Response.url}`);
361
+ }
362
+ let publicParams2048;
363
+ if (typeof publicParams2048Response.bytes === 'function') {
364
+ // bytes is not widely supported yet
365
+ publicParams2048 = await publicParams2048Response.bytes();
366
+ }
367
+ else {
368
+ publicParams2048 = new Uint8Array(await publicParams2048Response.arrayBuffer());
369
+ }
370
+ let pub_key;
371
+ try {
372
+ pub_key = TFHE.TfheCompactPublicKey.safe_deserialize(publicKey, SERIALIZED_SIZE_LIMIT_PK);
373
+ }
374
+ catch (e) {
375
+ throw new Error('Invalid public key (deserialization failed)', {
376
+ cause: e,
377
+ });
378
+ }
379
+ let crs;
380
+ try {
381
+ crs = TFHE.CompactPkeCrs.safe_deserialize(new Uint8Array(publicParams2048), SERIALIZED_SIZE_LIMIT_CRS);
125
382
  }
383
+ catch (e) {
384
+ throw new Error('Invalid crs (deserialization failed)', {
385
+ cause: e,
386
+ });
387
+ }
388
+ const result = {
389
+ publicKey: pub_key,
390
+ publicKeyId,
391
+ publicParams: {
392
+ 2048: {
393
+ publicParams: crs,
394
+ publicParamsId,
395
+ },
396
+ },
397
+ };
398
+ keyurlCache[url] = result;
399
+ return result;
400
+ // } else {
401
+ // throw new Error('No public key available');
402
+ // }
126
403
  }
127
404
  catch (e) {
128
405
  throw new Error('Impossible to fetch public key: wrong relayer url.', {
@@ -238,9 +515,6 @@ const NumEncryptedBits = {
238
515
  6: 128, // euint128
239
516
  7: 160, // eaddress
240
517
  8: 256, // euint256
241
- 9: 512, // ebytes64
242
- 10: 1024, // ebytes128
243
- 11: 2048, // ebytes256
244
518
  };
245
519
  function checkEncryptedBits(handles) {
246
520
  let total = 0;
@@ -263,6 +537,8 @@ function checkEncryptedBits(handles) {
263
537
  return total;
264
538
  }
265
539
 
540
+ // Add type checking
541
+ const getAddress$1 = (value) => getAddress$2(value);
266
542
  const aclABI$1 = [
267
543
  'function persistAllowed(bytes32 handle, address account) view returns (bool)',
268
544
  ];
@@ -275,7 +551,7 @@ function formatAccordingToType(decryptedBigInt, type) {
275
551
  }
276
552
  else if (type === 7) {
277
553
  // eaddress
278
- return getAddress('0x' + decryptedBigInt.toString(16).padStart(40, '0'));
554
+ return getAddress$1('0x' + decryptedBigInt.toString(16).padStart(40, '0'));
279
555
  }
280
556
  else if (type === 9) {
281
557
  // ebytes64
@@ -318,7 +594,16 @@ function checkDeadlineValidity(startTimestamp, durationDays) {
318
594
  throw Error('User decrypt request has expired');
319
595
  }
320
596
  }
321
- const userDecryptRequest = (kmsSigners, gatewayChainId, chainId, verifyingContractAddress, aclContractAddress, relayerUrl, provider) => async (_handles, privateKey, publicKey, signature, contractAddresses, userAddress, startTimestamp, durationDays) => {
597
+ const userDecryptRequest = (kmsSigners, gatewayChainId, chainId, verifyingContractAddress, aclContractAddress, relayerUrl, provider, options) => async (_handles, privateKey, publicKey, signature, contractAddresses, userAddress, startTimestamp, durationDays) => {
598
+ let pubKey;
599
+ let privKey;
600
+ try {
601
+ pubKey = TKMS.u8vec_to_ml_kem_pke_pk(fromHexString(publicKey));
602
+ privKey = TKMS.u8vec_to_ml_kem_pke_sk(fromHexString(privateKey));
603
+ }
604
+ catch (e) {
605
+ throw new Error('Invalid public or private key', { cause: e });
606
+ }
322
607
  // Casting handles if string
323
608
  const signatureSanitized = signature.replace(/^(0x)/, '');
324
609
  const publicKeySanitized = publicKey.replace(/^(0x)/, '');
@@ -326,7 +611,7 @@ const userDecryptRequest = (kmsSigners, gatewayChainId, chainId, verifyingContra
326
611
  handle: typeof h.handle === 'string'
327
612
  ? toHexString(fromHexString(h.handle), true)
328
613
  : toHexString(h.handle, true),
329
- contractAddress: h.contractAddress,
614
+ contractAddress: getAddress$1(h.contractAddress),
330
615
  }));
331
616
  checkEncryptedBits(handles.map((h) => h.handle));
332
617
  checkDeadlineValidity(BigInt(startTimestamp), BigInt(durationDays));
@@ -361,51 +646,12 @@ const userDecryptRequest = (kmsSigners, gatewayChainId, chainId, verifyingContra
361
646
  durationDays: durationDays.toString(), // Convert to string
362
647
  },
363
648
  contractsChainId: chainId.toString(), // Convert to string
364
- contractAddresses: contractAddresses.map((c) => getAddress(c)),
365
- userAddress: getAddress(userAddress),
649
+ contractAddresses: contractAddresses.map((c) => getAddress$1(c)),
650
+ userAddress: getAddress$1(userAddress),
366
651
  signature: signatureSanitized,
367
652
  publicKey: publicKeySanitized,
368
653
  };
369
- const options = {
370
- method: 'POST',
371
- headers: {
372
- 'Content-Type': 'application/json',
373
- },
374
- body: JSON.stringify(payloadForRequest),
375
- };
376
- let pubKey;
377
- let privKey;
378
- try {
379
- pubKey = TKMS.u8vec_to_ml_kem_pke_pk(fromHexString(publicKey));
380
- privKey = TKMS.u8vec_to_ml_kem_pke_sk(fromHexString(privateKey));
381
- }
382
- catch (e) {
383
- throw new Error('Invalid public or private key', { cause: e });
384
- }
385
- let response;
386
- let json;
387
- try {
388
- response = await fetch(`${relayerUrl}/v1/user-decrypt`, options);
389
- if (!response.ok) {
390
- throw new Error(`User decrypt failed: relayer respond with HTTP code ${response.status}`);
391
- }
392
- }
393
- catch (e) {
394
- throw new Error("User decrypt failed: Relayer didn't respond", {
395
- cause: e,
396
- });
397
- }
398
- try {
399
- json = await response.json();
400
- }
401
- catch (e) {
402
- throw new Error("User decrypt failed: Relayer didn't return a JSON", {
403
- cause: e,
404
- });
405
- }
406
- if (json.status === 'failure') {
407
- throw new Error("User decrypt failed: the user decryption didn't succeed for an unknown reason", { cause: json });
408
- }
654
+ const json = await fetchRelayerJsonRpcPost('USER_DECRYPT', `${relayerUrl}/v1/user-decrypt`, payloadForRequest, options);
409
655
  // assume the KMS Signers have the correct order
410
656
  let indexedKmsSigners = kmsSigners.map((signer, index) => {
411
657
  return TKMS.new_server_id_addr(index + 1, signer);
@@ -652,6 +898,8 @@ const computeHandles = (ciphertextWithZKProof, bitwidths, aclContractAddress, ch
652
898
  return handles;
653
899
  };
654
900
 
901
+ // Add type checking
902
+ const getAddress = (value) => getAddress$2(value);
655
903
  const currentCiphertextVersion = () => {
656
904
  return 0;
657
905
  };
@@ -671,6 +919,20 @@ function isThresholdReached$1(coprocessorSigners, recoveredAddresses, threshold)
671
919
  }
672
920
  return recoveredAddresses.length >= threshold;
673
921
  }
922
+ function isFhevmRelayerInputProofResponse(json) {
923
+ const response = json.response;
924
+ if (typeof response !== 'object' || response === null) {
925
+ return false;
926
+ }
927
+ if (!('handles' in response && Array.isArray(response.handles))) {
928
+ return false;
929
+ }
930
+ if (!('signatures' in response && Array.isArray(response.signatures))) {
931
+ return false;
932
+ }
933
+ return (response.signatures.every((s) => typeof s === 'string') &&
934
+ response.handles.every((h) => typeof h === 'string'));
935
+ }
674
936
  const createRelayerEncryptedInput = (aclContractAddress, verifyingContractAddressInputVerification, chainId, gatewayChainId, relayerUrl, tfheCompactPublicKey, publicParams, coprocessorSigners, thresholdCoprocessorSigners) => (contractAddress, userAddress) => {
675
937
  if (!isAddress(contractAddress)) {
676
938
  throw new Error('Contract address is not a valid address.');
@@ -716,18 +978,6 @@ const createRelayerEncryptedInput = (aclContractAddress, verifyingContractAddres
716
978
  input.add256(value);
717
979
  return this;
718
980
  },
719
- addBytes64(value) {
720
- input.addBytes64(value);
721
- return this;
722
- },
723
- addBytes128(value) {
724
- input.addBytes128(value);
725
- return this;
726
- },
727
- addBytes256(value) {
728
- input.addBytes256(value);
729
- return this;
730
- },
731
981
  addAddress(value) {
732
982
  input.addAddress(value);
733
983
  return this;
@@ -735,43 +985,18 @@ const createRelayerEncryptedInput = (aclContractAddress, verifyingContractAddres
735
985
  getBits() {
736
986
  return input.getBits();
737
987
  },
738
- encrypt: async () => {
988
+ encrypt: async (options) => {
739
989
  const bits = input.getBits();
740
990
  const ciphertext = input.encrypt();
741
- // https://github.com/zama-ai/fhevm-relayer/blob/978b08f62de060a9b50d2c6cc19fd71b5fb8d873/src/input_http_listener.rs#L13C1-L22C1
742
991
  const payload = {
743
992
  contractAddress: getAddress(contractAddress),
744
993
  userAddress: getAddress(userAddress),
745
994
  ciphertextWithInputVerification: toHexString(ciphertext),
746
- contractChainId: '0x' + chainId.toString(16),
995
+ contractChainId: ('0x' + chainId.toString(16)),
747
996
  };
748
- const options = {
749
- method: 'POST',
750
- headers: {
751
- 'Content-Type': 'application/json',
752
- },
753
- body: JSON.stringify(payload),
754
- };
755
- const url = `${relayerUrl}/v1/input-proof`;
756
- let json;
757
- try {
758
- const response = await fetch(url, options);
759
- if (!response.ok) {
760
- throw new Error(`Relayer didn't response correctly. Bad status ${response.statusText}. Content: ${await response.text()}`);
761
- }
762
- try {
763
- json = await response.json();
764
- }
765
- catch (e) {
766
- throw new Error("Relayer didn't response correctly. Bad JSON.", {
767
- cause: e,
768
- });
769
- }
770
- }
771
- catch (e) {
772
- throw new Error("Relayer didn't response correctly.", {
773
- cause: e,
774
- });
997
+ const json = await fetchRelayerJsonRpcPost('INPUT_PROOF', `${relayerUrl}/v1/input-proof`, payload, options);
998
+ if (!isFhevmRelayerInputProofResponse(json)) {
999
+ throwRelayerInternalError('INPUT_PROOF', json);
775
1000
  }
776
1001
  const handles = computeHandles(ciphertext, bits, aclContractAddress, chainId, currentCiphertextVersion());
777
1002
  // Note that the hex strings returned by the relayer do have have the 0x prefix
@@ -863,9 +1088,6 @@ const CiphertextType = {
863
1088
  6: 'uint256',
864
1089
  7: 'address',
865
1090
  8: 'uint256',
866
- 9: 'bytes',
867
- 10: 'bytes',
868
- 11: 'bytes',
869
1091
  };
870
1092
  function deserializeDecryptedResult(handles, decryptedResult) {
871
1093
  let typesList = [];
@@ -890,7 +1112,7 @@ function deserializeDecryptedResult(handles, decryptedResult) {
890
1112
  handles.forEach((handle, idx) => (results[handle] = rawValues[idx]));
891
1113
  return results;
892
1114
  }
893
- const publicDecryptRequest = (kmsSigners, thresholdSigners, gatewayChainId, verifyingContractAddress, aclContractAddress, relayerUrl, provider) => async (_handles) => {
1115
+ const publicDecryptRequest = (kmsSigners, thresholdSigners, gatewayChainId, verifyingContractAddress, aclContractAddress, relayerUrl, provider, options) => async (_handles) => {
894
1116
  const acl = new ethers.Contract(aclContractAddress, aclABI, provider);
895
1117
  let handles;
896
1118
  try {
@@ -908,51 +1130,12 @@ const publicDecryptRequest = (kmsSigners, thresholdSigners, gatewayChainId, veri
908
1130
  catch (e) {
909
1131
  throw e;
910
1132
  }
911
- const verifications = handles.map(async (ctHandle) => {
912
- const isAllowedForDecryption = await acl.isAllowedForDecryption(ctHandle);
913
- if (!isAllowedForDecryption) {
914
- throw new Error(`Handle ${ctHandle} is not allowed for public decryption!`);
915
- }
916
- });
917
- await Promise.all(verifications).catch((e) => {
918
- throw e;
919
- });
920
1133
  // check 2048 bits limit
921
1134
  checkEncryptedBits(handles);
922
1135
  const payloadForRequest = {
923
1136
  ciphertextHandles: handles,
924
1137
  };
925
- const options = {
926
- method: 'POST',
927
- headers: {
928
- 'Content-Type': 'application/json',
929
- },
930
- body: JSON.stringify(payloadForRequest),
931
- };
932
- let response;
933
- let json;
934
- try {
935
- response = await fetch(`${relayerUrl}/v1/public-decrypt`, options);
936
- if (!response.ok) {
937
- throw new Error(`Public decrypt failed: relayer respond with HTTP code ${response.status}`);
938
- }
939
- }
940
- catch (e) {
941
- throw new Error("Public decrypt failed: Relayer didn't respond", {
942
- cause: e,
943
- });
944
- }
945
- try {
946
- json = await response.json();
947
- }
948
- catch (e) {
949
- throw new Error("Public decrypt failed: Relayer didn't return a JSON", {
950
- cause: e,
951
- });
952
- }
953
- if (json.status === 'failure') {
954
- throw new Error("Public decrypt failed: the public decrypt didn't succeed for an unknown reason", { cause: json });
955
- }
1138
+ const json = await fetchRelayerJsonRpcPost('PUBLIC_DECRYPT', `${relayerUrl}/v1/public-decrypt`, payloadForRequest, options);
956
1139
  // verify signatures on decryption:
957
1140
  const domain = {
958
1141
  name: 'Decryption',
@@ -1180,4 +1363,4 @@ const createTfhePublicKey = () => {
1180
1363
  global.TFHE = TFHEPkg;
1181
1364
  global.TKMS = TKMSPkg;
1182
1365
 
1183
- export { ENCRYPTION_TYPES, SepoliaConfig, createEIP712, createInstance, createTfheKeypair, createTfhePublicKey, generateKeypair };
1366
+ export { ENCRYPTION_TYPES, SepoliaConfig, createEIP712, createInstance, createTfheKeypair, createTfhePublicKey, generateKeypair, getErrorCauseCode, getErrorCauseStatus };