@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.cjs CHANGED
@@ -44,7 +44,9 @@ const fromHexString = (hexString) => {
44
44
  return new Uint8Array();
45
45
  return Uint8Array.from(arr.map((byte) => parseInt(byte, 16)));
46
46
  };
47
- const toHexString = (bytes, with0x = false) => `${with0x ? '0x' : ''}${bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '')}`;
47
+ function toHexString(bytes, with0x = false) {
48
+ return `${with0x ? '0x' : ''}${bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '')}`;
49
+ }
48
50
  const bytesToBigInt = function (byteArray) {
49
51
  if (!byteArray || byteArray?.length === 0) {
50
52
  return BigInt(0);
@@ -55,95 +57,370 @@ const bytesToBigInt = function (byteArray) {
55
57
  return BigInt(`0x${hex}`);
56
58
  };
57
59
 
58
- const keyurlCache = {};
59
- const getKeysFromRelayer = async (url, publicKeyId) => {
60
- if (keyurlCache[url]) {
61
- return keyurlCache[url];
60
+ function getErrorCause(e) {
61
+ if (e instanceof Error && typeof e.cause === 'object' && e.cause !== null) {
62
+ return e.cause;
62
63
  }
63
- try {
64
- const response = await fetch(`${url}/v1/keyurl`);
65
- if (!response.ok) {
66
- throw new Error(`HTTP error! status: ${response.status}`);
67
- }
68
- const data = await response.json();
69
- if (data) {
70
- let pubKeyUrl;
71
- // If no publicKeyId is provided, use the first one
72
- // Warning: if there are multiple keys available, the first one will most likely never be the
73
- // same between several calls (fetching the infos is non-deterministic)
74
- if (!publicKeyId) {
75
- pubKeyUrl = data.response.fhe_key_info[0].fhe_public_key.urls[0];
76
- publicKeyId = data.response.fhe_key_info[0].fhe_public_key.data_id;
77
- }
78
- else {
79
- // If a publicKeyId is provided, get the corresponding info
80
- const keyInfo = data.response.fhe_key_info.find((info) => info.fhe_public_key.data_id === publicKeyId);
81
- if (!keyInfo) {
82
- throw new Error(`Could not find FHE key info with data_id ${publicKeyId}`);
83
- }
84
- // TODO: Get a given party's public key url instead of the first one
85
- pubKeyUrl = keyInfo.fhe_public_key.urls[0];
86
- }
87
- const publicKeyResponse = await fetch(pubKeyUrl);
88
- if (!publicKeyResponse.ok) {
89
- throw new Error(`HTTP error! status: ${publicKeyResponse.status} on ${publicKeyResponse.url}`);
90
- }
91
- let publicKey;
92
- if (typeof publicKeyResponse.bytes === 'function') {
93
- // bytes is not widely supported yet
94
- publicKey = await publicKeyResponse.bytes();
95
- }
96
- else {
97
- publicKey = new Uint8Array(await publicKeyResponse.arrayBuffer());
64
+ return undefined;
65
+ }
66
+ function getErrorCauseCode(e) {
67
+ const cause = getErrorCause(e);
68
+ if (!cause || !('code' in cause) || !cause.code) {
69
+ return undefined;
70
+ }
71
+ if (typeof cause.code !== 'string') {
72
+ return undefined;
73
+ }
74
+ return cause.code;
75
+ }
76
+ function getErrorCauseStatus(e) {
77
+ const cause = getErrorCause(e);
78
+ if (!cause || !('status' in cause) || cause.status === undefined) {
79
+ return undefined;
80
+ }
81
+ if (typeof cause.status !== 'number') {
82
+ return undefined;
83
+ }
84
+ return cause.status;
85
+ }
86
+ async function throwRelayerResponseError(operation, response) {
87
+ let message;
88
+ // Special case for 429
89
+ if (response.status === 429) {
90
+ message = `Relayer rate limit exceeded: Please wait and try again later.`;
91
+ }
92
+ else {
93
+ switch (operation) {
94
+ case 'PUBLIC_DECRYPT': {
95
+ message = `Public decrypt failed: relayer respond with HTTP code ${response.status}`;
96
+ break;
98
97
  }
99
- const publicParamsUrl = data.response.crs['2048'].urls[0];
100
- const publicParamsId = data.response.crs['2048'].data_id;
101
- const publicParams2048Response = await fetch(publicParamsUrl);
102
- if (!publicParams2048Response.ok) {
103
- throw new Error(`HTTP error! status: ${publicParams2048Response.status} on ${publicParams2048Response.url}`);
98
+ case 'USER_DECRYPT': {
99
+ message = `User decrypt failed: relayer respond with HTTP code ${response.status}`;
100
+ break;
104
101
  }
105
- let publicParams2048;
106
- if (typeof publicParams2048Response.bytes === 'function') {
107
- // bytes is not widely supported yet
108
- publicParams2048 = await publicParams2048Response.bytes();
102
+ case 'KEY_URL': {
103
+ message = `HTTP error! status: ${response.status}`;
104
+ break;
109
105
  }
110
- else {
111
- publicParams2048 = new Uint8Array(await publicParams2048Response.arrayBuffer());
106
+ default: {
107
+ const responseText = await response.text();
108
+ message = `Relayer didn't response correctly. Bad status ${response.statusText}. Content: ${responseText}`;
109
+ break;
112
110
  }
113
- let pub_key;
114
- try {
115
- pub_key = TFHE.TfheCompactPublicKey.safe_deserialize(publicKey, SERIALIZED_SIZE_LIMIT_PK);
111
+ }
112
+ }
113
+ const cause = {
114
+ code: 'RELAYER_FETCH_ERROR',
115
+ operation,
116
+ status: response.status,
117
+ statusText: response.statusText,
118
+ url: response.url,
119
+ };
120
+ throw new Error(message, {
121
+ cause,
122
+ });
123
+ }
124
+ function throwRelayerJSONError(operation, error) {
125
+ let message;
126
+ switch (operation) {
127
+ case 'PUBLIC_DECRYPT': {
128
+ message = "Public decrypt failed: Relayer didn't return a JSON";
129
+ break;
130
+ }
131
+ case 'USER_DECRYPT': {
132
+ message = "User decrypt failed: Relayer didn't return a JSON";
133
+ break;
134
+ }
135
+ default: {
136
+ message = "Relayer didn't return a JSON";
137
+ break;
138
+ }
139
+ }
140
+ const cause = {
141
+ code: 'RELAYER_NO_JSON_ERROR',
142
+ operation,
143
+ error,
144
+ };
145
+ throw new Error(message, {
146
+ cause,
147
+ });
148
+ }
149
+ function throwRelayerUnexpectedJSONError(operation, error) {
150
+ let message;
151
+ switch (operation) {
152
+ case 'PUBLIC_DECRYPT': {
153
+ message =
154
+ 'Public decrypt failed: Relayer returned an unexpected JSON response';
155
+ break;
156
+ }
157
+ case 'USER_DECRYPT': {
158
+ message =
159
+ 'User decrypt failed: Relayer returned an unexpected JSON response';
160
+ break;
161
+ }
162
+ default: {
163
+ message = 'Relayer returned an unexpected JSON response';
164
+ break;
165
+ }
166
+ }
167
+ const cause = {
168
+ code: 'RELAYER_UNEXPECTED_JSON_ERROR',
169
+ operation,
170
+ error,
171
+ };
172
+ throw new Error(message, {
173
+ cause,
174
+ });
175
+ }
176
+ function throwRelayerInternalError(operation, json) {
177
+ let message;
178
+ switch (operation) {
179
+ case 'PUBLIC_DECRYPT': {
180
+ message =
181
+ "Pulbic decrypt failed: the public decryption didn't succeed for an unknown reason";
182
+ break;
183
+ }
184
+ case 'USER_DECRYPT': {
185
+ message =
186
+ "User decrypt failed: the user decryption didn't succeed for an unknown reason";
187
+ break;
188
+ }
189
+ default: {
190
+ message = "Relayer didn't response correctly.";
191
+ break;
192
+ }
193
+ }
194
+ const cause = {
195
+ code: 'RELAYER_INTERNAL_ERROR',
196
+ operation,
197
+ error: json,
198
+ };
199
+ throw new Error(message, {
200
+ cause,
201
+ });
202
+ }
203
+ function throwRelayerUnknownError(operation, error, message) {
204
+ if (!message) {
205
+ switch (operation) {
206
+ case 'PUBLIC_DECRYPT': {
207
+ message = "Public decrypt failed: Relayer didn't respond";
208
+ break;
116
209
  }
117
- catch (e) {
118
- throw new Error('Invalid public key (deserialization failed)', {
119
- cause: e,
120
- });
210
+ case 'USER_DECRYPT': {
211
+ message = "User decrypt failed: Relayer didn't respond";
212
+ break;
121
213
  }
122
- let crs;
123
- try {
124
- crs = TFHE.CompactPkeCrs.safe_deserialize(new Uint8Array(publicParams2048), SERIALIZED_SIZE_LIMIT_CRS);
214
+ default: {
215
+ message = "Relayer didn't response correctly. Bad JSON.";
216
+ break;
125
217
  }
126
- catch (e) {
127
- throw new Error('Invalid crs (deserialization failed)', {
128
- cause: e,
129
- });
218
+ }
219
+ }
220
+ const cause = {
221
+ code: 'RELAYER_UNKNOWN_ERROR',
222
+ operation,
223
+ error,
224
+ };
225
+ throw new Error(message ?? "Relayer didn't response correctly.", {
226
+ cause,
227
+ });
228
+ }
229
+
230
+ function assertIsRelayerFetchResponseJson(json) {
231
+ if (!json || typeof json !== 'object') {
232
+ throw new Error('Unexpected response JSON.');
233
+ }
234
+ if (!('response' in json &&
235
+ json.response !== null &&
236
+ json.response !== undefined)) {
237
+ throw new Error("Unexpected response JSON format: missing 'response' property.");
238
+ }
239
+ }
240
+ async function fetchRelayerJsonRpcPost(relayerOperation, url, payload, options) {
241
+ const init = {
242
+ method: 'POST',
243
+ headers: {
244
+ 'Content-Type': 'application/json',
245
+ ...(options?.apiKey && { 'x-api-key': options.apiKey }),
246
+ },
247
+ body: JSON.stringify(payload),
248
+ };
249
+ let response;
250
+ let json;
251
+ try {
252
+ response = await fetch(url, init);
253
+ }
254
+ catch (e) {
255
+ throwRelayerUnknownError(relayerOperation, e);
256
+ }
257
+ if (!response.ok) {
258
+ await throwRelayerResponseError(relayerOperation, response);
259
+ }
260
+ let parsed;
261
+ try {
262
+ parsed = await response.json();
263
+ }
264
+ catch (e) {
265
+ throwRelayerJSONError(relayerOperation, e);
266
+ }
267
+ try {
268
+ assertIsRelayerFetchResponseJson(parsed);
269
+ json = parsed;
270
+ }
271
+ catch (e) {
272
+ throwRelayerUnexpectedJSONError(relayerOperation, e);
273
+ }
274
+ return json;
275
+ }
276
+ async function fetchRelayerGet(relayerOperation, url) {
277
+ let response;
278
+ let json;
279
+ try {
280
+ response = await fetch(url);
281
+ }
282
+ catch (e) {
283
+ throwRelayerUnknownError(relayerOperation, e);
284
+ }
285
+ if (!response.ok) {
286
+ await throwRelayerResponseError(relayerOperation, response);
287
+ }
288
+ let parsed;
289
+ try {
290
+ parsed = await response.json();
291
+ }
292
+ catch (e) {
293
+ throwRelayerJSONError(relayerOperation, e);
294
+ }
295
+ try {
296
+ assertIsRelayerFetchResponseJson(parsed);
297
+ json = parsed;
298
+ }
299
+ catch (e) {
300
+ throwRelayerUnexpectedJSONError(relayerOperation, e);
301
+ }
302
+ return json;
303
+ }
304
+
305
+ // export type RelayerKeysItem = {
306
+ // data_id: string;
307
+ // param_choice: number;
308
+ // urls: string[];
309
+ // signatures: string[];
310
+ // };
311
+ // export type RelayerKey = {
312
+ // data_id: string;
313
+ // param_choice: number;
314
+ // signatures: string[];
315
+ // urls: string[];
316
+ // };
317
+ // export type RelayerKeys = {
318
+ // response: {
319
+ // fhe_key_info: {
320
+ // fhe_public_key: RelayerKey;
321
+ // fhe_server_key: RelayerKey;
322
+ // }[];
323
+ // verf_public_key: {
324
+ // key_id: string;
325
+ // server_id: number;
326
+ // verf_public_key_address: string;
327
+ // verf_public_key_url: string;
328
+ // }[];
329
+ // crs: {
330
+ // [key: string]: RelayerKeysItem;
331
+ // };
332
+ // };
333
+ // status: string;
334
+ // };
335
+ const keyurlCache = {};
336
+ const getKeysFromRelayer = async (url, publicKeyId) => {
337
+ if (keyurlCache[url]) {
338
+ return keyurlCache[url];
339
+ }
340
+ const data = await fetchRelayerGet('KEY_URL', `${url}/v1/keyurl`);
341
+ try {
342
+ // const response = await fetch(`${url}/v1/keyurl`);
343
+ // if (!response.ok) {
344
+ // await throwRelayerResponseError("KEY_URL", response);
345
+ // }
346
+ //const data: RelayerKeys = await response.json();
347
+ //if (data) {
348
+ let pubKeyUrl;
349
+ // If no publicKeyId is provided, use the first one
350
+ // Warning: if there are multiple keys available, the first one will most likely never be the
351
+ // same between several calls (fetching the infos is non-deterministic)
352
+ if (!publicKeyId) {
353
+ pubKeyUrl = data.response.fhe_key_info[0].fhe_public_key.urls[0];
354
+ publicKeyId = data.response.fhe_key_info[0].fhe_public_key.data_id;
355
+ }
356
+ else {
357
+ // If a publicKeyId is provided, get the corresponding info
358
+ const keyInfo = data.response.fhe_key_info.find((info) => info.fhe_public_key.data_id === publicKeyId);
359
+ if (!keyInfo) {
360
+ throw new Error(`Could not find FHE key info with data_id ${publicKeyId}`);
130
361
  }
131
- const result = {
132
- publicKey: pub_key,
133
- publicKeyId,
134
- publicParams: {
135
- 2048: {
136
- publicParams: crs,
137
- publicParamsId,
138
- },
139
- },
140
- };
141
- keyurlCache[url] = result;
142
- return result;
362
+ // TODO: Get a given party's public key url instead of the first one
363
+ pubKeyUrl = keyInfo.fhe_public_key.urls[0];
364
+ }
365
+ const publicKeyResponse = await fetch(pubKeyUrl);
366
+ if (!publicKeyResponse.ok) {
367
+ throw new Error(`HTTP error! status: ${publicKeyResponse.status} on ${publicKeyResponse.url}`);
368
+ }
369
+ let publicKey;
370
+ if (typeof publicKeyResponse.bytes === 'function') {
371
+ // bytes is not widely supported yet
372
+ publicKey = await publicKeyResponse.bytes();
143
373
  }
144
374
  else {
145
- throw new Error('No public key available');
375
+ publicKey = new Uint8Array(await publicKeyResponse.arrayBuffer());
376
+ }
377
+ const publicParamsUrl = data.response.crs['2048'].urls[0];
378
+ const publicParamsId = data.response.crs['2048'].data_id;
379
+ const publicParams2048Response = await fetch(publicParamsUrl);
380
+ if (!publicParams2048Response.ok) {
381
+ throw new Error(`HTTP error! status: ${publicParams2048Response.status} on ${publicParams2048Response.url}`);
382
+ }
383
+ let publicParams2048;
384
+ if (typeof publicParams2048Response.bytes === 'function') {
385
+ // bytes is not widely supported yet
386
+ publicParams2048 = await publicParams2048Response.bytes();
387
+ }
388
+ else {
389
+ publicParams2048 = new Uint8Array(await publicParams2048Response.arrayBuffer());
390
+ }
391
+ let pub_key;
392
+ try {
393
+ pub_key = TFHE.TfheCompactPublicKey.safe_deserialize(publicKey, SERIALIZED_SIZE_LIMIT_PK);
394
+ }
395
+ catch (e) {
396
+ throw new Error('Invalid public key (deserialization failed)', {
397
+ cause: e,
398
+ });
399
+ }
400
+ let crs;
401
+ try {
402
+ crs = TFHE.CompactPkeCrs.safe_deserialize(new Uint8Array(publicParams2048), SERIALIZED_SIZE_LIMIT_CRS);
146
403
  }
404
+ catch (e) {
405
+ throw new Error('Invalid crs (deserialization failed)', {
406
+ cause: e,
407
+ });
408
+ }
409
+ const result = {
410
+ publicKey: pub_key,
411
+ publicKeyId,
412
+ publicParams: {
413
+ 2048: {
414
+ publicParams: crs,
415
+ publicParamsId,
416
+ },
417
+ },
418
+ };
419
+ keyurlCache[url] = result;
420
+ return result;
421
+ // } else {
422
+ // throw new Error('No public key available');
423
+ // }
147
424
  }
148
425
  catch (e) {
149
426
  throw new Error('Impossible to fetch public key: wrong relayer url.', {
@@ -259,9 +536,6 @@ const NumEncryptedBits = {
259
536
  6: 128, // euint128
260
537
  7: 160, // eaddress
261
538
  8: 256, // euint256
262
- 9: 512, // ebytes64
263
- 10: 1024, // ebytes128
264
- 11: 2048, // ebytes256
265
539
  };
266
540
  function checkEncryptedBits(handles) {
267
541
  let total = 0;
@@ -284,6 +558,8 @@ function checkEncryptedBits(handles) {
284
558
  return total;
285
559
  }
286
560
 
561
+ // Add type checking
562
+ const getAddress$1 = (value) => ethers.getAddress(value);
287
563
  const aclABI$1 = [
288
564
  'function persistAllowed(bytes32 handle, address account) view returns (bool)',
289
565
  ];
@@ -296,7 +572,7 @@ function formatAccordingToType(decryptedBigInt, type) {
296
572
  }
297
573
  else if (type === 7) {
298
574
  // eaddress
299
- return ethers.getAddress('0x' + decryptedBigInt.toString(16).padStart(40, '0'));
575
+ return getAddress$1('0x' + decryptedBigInt.toString(16).padStart(40, '0'));
300
576
  }
301
577
  else if (type === 9) {
302
578
  // ebytes64
@@ -339,7 +615,16 @@ function checkDeadlineValidity(startTimestamp, durationDays) {
339
615
  throw Error('User decrypt request has expired');
340
616
  }
341
617
  }
342
- const userDecryptRequest = (kmsSigners, gatewayChainId, chainId, verifyingContractAddress, aclContractAddress, relayerUrl, provider) => async (_handles, privateKey, publicKey, signature, contractAddresses, userAddress, startTimestamp, durationDays) => {
618
+ const userDecryptRequest = (kmsSigners, gatewayChainId, chainId, verifyingContractAddress, aclContractAddress, relayerUrl, provider, options) => async (_handles, privateKey, publicKey, signature, contractAddresses, userAddress, startTimestamp, durationDays) => {
619
+ let pubKey;
620
+ let privKey;
621
+ try {
622
+ pubKey = TKMS.u8vec_to_ml_kem_pke_pk(fromHexString(publicKey));
623
+ privKey = TKMS.u8vec_to_ml_kem_pke_sk(fromHexString(privateKey));
624
+ }
625
+ catch (e) {
626
+ throw new Error('Invalid public or private key', { cause: e });
627
+ }
343
628
  // Casting handles if string
344
629
  const signatureSanitized = signature.replace(/^(0x)/, '');
345
630
  const publicKeySanitized = publicKey.replace(/^(0x)/, '');
@@ -347,7 +632,7 @@ const userDecryptRequest = (kmsSigners, gatewayChainId, chainId, verifyingContra
347
632
  handle: typeof h.handle === 'string'
348
633
  ? toHexString(fromHexString(h.handle), true)
349
634
  : toHexString(h.handle, true),
350
- contractAddress: h.contractAddress,
635
+ contractAddress: getAddress$1(h.contractAddress),
351
636
  }));
352
637
  checkEncryptedBits(handles.map((h) => h.handle));
353
638
  checkDeadlineValidity(BigInt(startTimestamp), BigInt(durationDays));
@@ -382,51 +667,12 @@ const userDecryptRequest = (kmsSigners, gatewayChainId, chainId, verifyingContra
382
667
  durationDays: durationDays.toString(), // Convert to string
383
668
  },
384
669
  contractsChainId: chainId.toString(), // Convert to string
385
- contractAddresses: contractAddresses.map((c) => ethers.getAddress(c)),
386
- userAddress: ethers.getAddress(userAddress),
670
+ contractAddresses: contractAddresses.map((c) => getAddress$1(c)),
671
+ userAddress: getAddress$1(userAddress),
387
672
  signature: signatureSanitized,
388
673
  publicKey: publicKeySanitized,
389
674
  };
390
- const options = {
391
- method: 'POST',
392
- headers: {
393
- 'Content-Type': 'application/json',
394
- },
395
- body: JSON.stringify(payloadForRequest),
396
- };
397
- let pubKey;
398
- let privKey;
399
- try {
400
- pubKey = TKMS.u8vec_to_ml_kem_pke_pk(fromHexString(publicKey));
401
- privKey = TKMS.u8vec_to_ml_kem_pke_sk(fromHexString(privateKey));
402
- }
403
- catch (e) {
404
- throw new Error('Invalid public or private key', { cause: e });
405
- }
406
- let response;
407
- let json;
408
- try {
409
- response = await fetch(`${relayerUrl}/v1/user-decrypt`, options);
410
- if (!response.ok) {
411
- throw new Error(`User decrypt failed: relayer respond with HTTP code ${response.status}`);
412
- }
413
- }
414
- catch (e) {
415
- throw new Error("User decrypt failed: Relayer didn't respond", {
416
- cause: e,
417
- });
418
- }
419
- try {
420
- json = await response.json();
421
- }
422
- catch (e) {
423
- throw new Error("User decrypt failed: Relayer didn't return a JSON", {
424
- cause: e,
425
- });
426
- }
427
- if (json.status === 'failure') {
428
- throw new Error("User decrypt failed: the user decryption didn't succeed for an unknown reason", { cause: json });
429
- }
675
+ const json = await fetchRelayerJsonRpcPost('USER_DECRYPT', `${relayerUrl}/v1/user-decrypt`, payloadForRequest, options);
430
676
  // assume the KMS Signers have the correct order
431
677
  let indexedKmsSigners = kmsSigners.map((signer, index) => {
432
678
  return TKMS.new_server_id_addr(index + 1, signer);
@@ -673,6 +919,8 @@ const computeHandles = (ciphertextWithZKProof, bitwidths, aclContractAddress, ch
673
919
  return handles;
674
920
  };
675
921
 
922
+ // Add type checking
923
+ const getAddress = (value) => ethers.getAddress(value);
676
924
  const currentCiphertextVersion = () => {
677
925
  return 0;
678
926
  };
@@ -692,6 +940,20 @@ function isThresholdReached$1(coprocessorSigners, recoveredAddresses, threshold)
692
940
  }
693
941
  return recoveredAddresses.length >= threshold;
694
942
  }
943
+ function isFhevmRelayerInputProofResponse(json) {
944
+ const response = json.response;
945
+ if (typeof response !== 'object' || response === null) {
946
+ return false;
947
+ }
948
+ if (!('handles' in response && Array.isArray(response.handles))) {
949
+ return false;
950
+ }
951
+ if (!('signatures' in response && Array.isArray(response.signatures))) {
952
+ return false;
953
+ }
954
+ return (response.signatures.every((s) => typeof s === 'string') &&
955
+ response.handles.every((h) => typeof h === 'string'));
956
+ }
695
957
  const createRelayerEncryptedInput = (aclContractAddress, verifyingContractAddressInputVerification, chainId, gatewayChainId, relayerUrl, tfheCompactPublicKey, publicParams, coprocessorSigners, thresholdCoprocessorSigners) => (contractAddress, userAddress) => {
696
958
  if (!ethers.isAddress(contractAddress)) {
697
959
  throw new Error('Contract address is not a valid address.');
@@ -737,18 +999,6 @@ const createRelayerEncryptedInput = (aclContractAddress, verifyingContractAddres
737
999
  input.add256(value);
738
1000
  return this;
739
1001
  },
740
- addBytes64(value) {
741
- input.addBytes64(value);
742
- return this;
743
- },
744
- addBytes128(value) {
745
- input.addBytes128(value);
746
- return this;
747
- },
748
- addBytes256(value) {
749
- input.addBytes256(value);
750
- return this;
751
- },
752
1002
  addAddress(value) {
753
1003
  input.addAddress(value);
754
1004
  return this;
@@ -756,43 +1006,18 @@ const createRelayerEncryptedInput = (aclContractAddress, verifyingContractAddres
756
1006
  getBits() {
757
1007
  return input.getBits();
758
1008
  },
759
- encrypt: async () => {
1009
+ encrypt: async (options) => {
760
1010
  const bits = input.getBits();
761
1011
  const ciphertext = input.encrypt();
762
- // https://github.com/zama-ai/fhevm-relayer/blob/978b08f62de060a9b50d2c6cc19fd71b5fb8d873/src/input_http_listener.rs#L13C1-L22C1
763
1012
  const payload = {
764
- contractAddress: ethers.getAddress(contractAddress),
765
- userAddress: ethers.getAddress(userAddress),
1013
+ contractAddress: getAddress(contractAddress),
1014
+ userAddress: getAddress(userAddress),
766
1015
  ciphertextWithInputVerification: toHexString(ciphertext),
767
- contractChainId: '0x' + chainId.toString(16),
1016
+ contractChainId: ('0x' + chainId.toString(16)),
768
1017
  };
769
- const options = {
770
- method: 'POST',
771
- headers: {
772
- 'Content-Type': 'application/json',
773
- },
774
- body: JSON.stringify(payload),
775
- };
776
- const url = `${relayerUrl}/v1/input-proof`;
777
- let json;
778
- try {
779
- const response = await fetch(url, options);
780
- if (!response.ok) {
781
- throw new Error(`Relayer didn't response correctly. Bad status ${response.statusText}. Content: ${await response.text()}`);
782
- }
783
- try {
784
- json = await response.json();
785
- }
786
- catch (e) {
787
- throw new Error("Relayer didn't response correctly. Bad JSON.", {
788
- cause: e,
789
- });
790
- }
791
- }
792
- catch (e) {
793
- throw new Error("Relayer didn't response correctly.", {
794
- cause: e,
795
- });
1018
+ const json = await fetchRelayerJsonRpcPost('INPUT_PROOF', `${relayerUrl}/v1/input-proof`, payload, options);
1019
+ if (!isFhevmRelayerInputProofResponse(json)) {
1020
+ throwRelayerInternalError('INPUT_PROOF', json);
796
1021
  }
797
1022
  const handles = computeHandles(ciphertext, bits, aclContractAddress, chainId, currentCiphertextVersion());
798
1023
  // Note that the hex strings returned by the relayer do have have the 0x prefix
@@ -884,9 +1109,6 @@ const CiphertextType = {
884
1109
  6: 'uint256',
885
1110
  7: 'address',
886
1111
  8: 'uint256',
887
- 9: 'bytes',
888
- 10: 'bytes',
889
- 11: 'bytes',
890
1112
  };
891
1113
  function deserializeDecryptedResult(handles, decryptedResult) {
892
1114
  let typesList = [];
@@ -911,7 +1133,7 @@ function deserializeDecryptedResult(handles, decryptedResult) {
911
1133
  handles.forEach((handle, idx) => (results[handle] = rawValues[idx]));
912
1134
  return results;
913
1135
  }
914
- const publicDecryptRequest = (kmsSigners, thresholdSigners, gatewayChainId, verifyingContractAddress, aclContractAddress, relayerUrl, provider) => async (_handles) => {
1136
+ const publicDecryptRequest = (kmsSigners, thresholdSigners, gatewayChainId, verifyingContractAddress, aclContractAddress, relayerUrl, provider, options) => async (_handles) => {
915
1137
  const acl = new ethers.ethers.Contract(aclContractAddress, aclABI, provider);
916
1138
  let handles;
917
1139
  try {
@@ -929,51 +1151,12 @@ const publicDecryptRequest = (kmsSigners, thresholdSigners, gatewayChainId, veri
929
1151
  catch (e) {
930
1152
  throw e;
931
1153
  }
932
- const verifications = handles.map(async (ctHandle) => {
933
- const isAllowedForDecryption = await acl.isAllowedForDecryption(ctHandle);
934
- if (!isAllowedForDecryption) {
935
- throw new Error(`Handle ${ctHandle} is not allowed for public decryption!`);
936
- }
937
- });
938
- await Promise.all(verifications).catch((e) => {
939
- throw e;
940
- });
941
1154
  // check 2048 bits limit
942
1155
  checkEncryptedBits(handles);
943
1156
  const payloadForRequest = {
944
1157
  ciphertextHandles: handles,
945
1158
  };
946
- const options = {
947
- method: 'POST',
948
- headers: {
949
- 'Content-Type': 'application/json',
950
- },
951
- body: JSON.stringify(payloadForRequest),
952
- };
953
- let response;
954
- let json;
955
- try {
956
- response = await fetch(`${relayerUrl}/v1/public-decrypt`, options);
957
- if (!response.ok) {
958
- throw new Error(`Public decrypt failed: relayer respond with HTTP code ${response.status}`);
959
- }
960
- }
961
- catch (e) {
962
- throw new Error("Public decrypt failed: Relayer didn't respond", {
963
- cause: e,
964
- });
965
- }
966
- try {
967
- json = await response.json();
968
- }
969
- catch (e) {
970
- throw new Error("Public decrypt failed: Relayer didn't return a JSON", {
971
- cause: e,
972
- });
973
- }
974
- if (json.status === 'failure') {
975
- throw new Error("Public decrypt failed: the public decrypt didn't succeed for an unknown reason", { cause: json });
976
- }
1159
+ const json = await fetchRelayerJsonRpcPost('PUBLIC_DECRYPT', `${relayerUrl}/v1/public-decrypt`, payloadForRequest, options);
977
1160
  // verify signatures on decryption:
978
1161
  const domain = {
979
1162
  name: 'Decryption',
@@ -1208,3 +1391,5 @@ exports.createInstance = createInstance;
1208
1391
  exports.createTfheKeypair = createTfheKeypair;
1209
1392
  exports.createTfhePublicKey = createTfhePublicKey;
1210
1393
  exports.generateKeypair = generateKeypair;
1394
+ exports.getErrorCauseCode = getErrorCauseCode;
1395
+ exports.getErrorCauseStatus = getErrorCauseStatus;