@zama-fhe/relayer-sdk 0.4.0-alpha.0 → 0.4.0-alpha.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/bin/commands/config.js +13 -0
- package/bin/commands/handle.js +22 -0
- package/bin/commands/input-proof.js +75 -0
- package/bin/commands/pubkey-clear.js +18 -0
- package/bin/commands/pubkey-fetch.js +9 -0
- package/bin/commands/pubkey-info.js +44 -0
- package/bin/commands/public-decrypt.js +64 -0
- package/bin/commands/test-fhecounter-getcount.js +49 -0
- package/bin/commands/zkproof-generate.js +68 -0
- package/bin/instance.js +15 -0
- package/bin/pubkeyCache.js +126 -0
- package/bin/relayer.js +132 -59
- package/bin/utils.js +345 -8
- package/bundle/relayer-sdk-js.js +6322 -5578
- package/bundle/relayer-sdk-js.umd.cjs +5 -5
- package/bundle.d.ts +1 -1
- package/lib/internal.js +6138 -0
- package/lib/node.cjs +1263 -380
- package/lib/node.d.ts +40 -114
- package/lib/node.js +1264 -381
- package/lib/web.d.ts +40 -114
- package/lib/web.js +1263 -380
- package/package.json +5 -2
package/lib/node.js
CHANGED
|
@@ -1,37 +1,15 @@
|
|
|
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, getAddress as getAddress$2,
|
|
4
|
+
import { JsonRpcProvider, BrowserProvider, Contract, getAddress as getAddress$2, isAddress as isAddress$1, keccak256, ethers, AbiCoder } from 'ethers';
|
|
5
5
|
|
|
6
6
|
const SERIALIZED_SIZE_LIMIT_CIPHERTEXT = BigInt(1024 * 1024 * 512);
|
|
7
7
|
const SERIALIZED_SIZE_LIMIT_PK = BigInt(1024 * 1024 * 512);
|
|
8
8
|
const SERIALIZED_SIZE_LIMIT_CRS = BigInt(1024 * 1024 * 512);
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
case 'BearerToken':
|
|
14
|
-
init.headers['Authorization'] =
|
|
15
|
-
`Bearer ${auth.token}`;
|
|
16
|
-
break;
|
|
17
|
-
case 'ApiKeyHeader':
|
|
18
|
-
init.headers[auth.header || 'x-api-key'] =
|
|
19
|
-
auth.value;
|
|
20
|
-
break;
|
|
21
|
-
case 'ApiKeyCookie':
|
|
22
|
-
if (typeof window !== 'undefined') {
|
|
23
|
-
document.cookie = `${auth.cookie || 'x-api-key'}=${auth.value}; path=/; SameSite=Lax; Secure; HttpOnly;`;
|
|
24
|
-
init.credentials = 'include';
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
27
|
-
let cookie = `${auth.cookie || 'x-api-key'}=${auth.value};`;
|
|
28
|
-
init.headers['Cookie'] = cookie;
|
|
29
|
-
}
|
|
30
|
-
break;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
return init;
|
|
34
|
-
}
|
|
10
|
+
// This file is auto-generated
|
|
11
|
+
const version = '0.4.0-alpha.2';
|
|
12
|
+
const sdkName = '@zama-fhe/relayer-sdk';
|
|
35
13
|
|
|
36
14
|
function getErrorCause(e) {
|
|
37
15
|
if (e instanceof Error && typeof e.cause === 'object' && e.cause !== null) {
|
|
@@ -213,7 +191,39 @@ function throwRelayerUnknownError(operation, error, message) {
|
|
|
213
191
|
});
|
|
214
192
|
}
|
|
215
193
|
|
|
216
|
-
|
|
194
|
+
/**
|
|
195
|
+
* Set the authentication method for the request. The default is no authentication.
|
|
196
|
+
* It supports:
|
|
197
|
+
* - Bearer Token
|
|
198
|
+
* - Custom header
|
|
199
|
+
* - Custom cookie
|
|
200
|
+
*/
|
|
201
|
+
function setAuth(init, auth) {
|
|
202
|
+
if (auth) {
|
|
203
|
+
switch (auth.__type) {
|
|
204
|
+
case 'BearerToken':
|
|
205
|
+
init.headers['Authorization'] =
|
|
206
|
+
`Bearer ${auth.token}`;
|
|
207
|
+
break;
|
|
208
|
+
case 'ApiKeyHeader':
|
|
209
|
+
init.headers[auth.header || 'x-api-key'] =
|
|
210
|
+
auth.value;
|
|
211
|
+
break;
|
|
212
|
+
case 'ApiKeyCookie':
|
|
213
|
+
if (typeof window !== 'undefined') {
|
|
214
|
+
document.cookie = `${auth.cookie || 'x-api-key'}=${auth.value}; path=/; SameSite=Lax; Secure; HttpOnly;`;
|
|
215
|
+
init.credentials = 'include';
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
let cookie = `${auth.cookie || 'x-api-key'}=${auth.value};`;
|
|
219
|
+
init.headers['Cookie'] = cookie;
|
|
220
|
+
}
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return init;
|
|
225
|
+
}
|
|
226
|
+
|
|
217
227
|
function assertIsRelayerV1FetchResponseJson(json) {
|
|
218
228
|
if (!json || typeof json !== 'object') {
|
|
219
229
|
throw new Error('Unexpected response JSON.');
|
|
@@ -224,11 +234,13 @@ function assertIsRelayerV1FetchResponseJson(json) {
|
|
|
224
234
|
throw new Error("Unexpected response JSON format: missing 'response' property.");
|
|
225
235
|
}
|
|
226
236
|
}
|
|
227
|
-
async function
|
|
237
|
+
async function fetchRelayerV1Post(relayerOperation, url, payload, options) {
|
|
228
238
|
const init = setAuth({
|
|
229
239
|
method: 'POST',
|
|
230
240
|
headers: {
|
|
231
241
|
'Content-Type': 'application/json',
|
|
242
|
+
'ZAMA-SDK-VERSION': `${version}`,
|
|
243
|
+
'ZAMA-SDK-NAME': `${sdkName}`,
|
|
232
244
|
},
|
|
233
245
|
body: JSON.stringify(payload),
|
|
234
246
|
}, options?.auth);
|
|
@@ -259,14 +271,20 @@ async function fetchRelayerJsonRpcPost(relayerOperation, url, payload, options)
|
|
|
259
271
|
}
|
|
260
272
|
return json;
|
|
261
273
|
}
|
|
262
|
-
async function
|
|
274
|
+
async function fetchRelayerV1Get(relayerOperation, url) {
|
|
275
|
+
const init = {
|
|
276
|
+
method: 'GET',
|
|
277
|
+
headers: {
|
|
278
|
+
'ZAMA-SDK-VERSION': `${version}`,
|
|
279
|
+
'ZAMA-SDK-NAME': `${sdkName}`,
|
|
280
|
+
},
|
|
281
|
+
};
|
|
263
282
|
let response;
|
|
264
283
|
let json;
|
|
265
284
|
try {
|
|
266
|
-
response = await fetch(url);
|
|
285
|
+
response = await fetch(url, init);
|
|
267
286
|
}
|
|
268
287
|
catch (e) {
|
|
269
|
-
console.log(e);
|
|
270
288
|
throwRelayerUnknownError(relayerOperation, e);
|
|
271
289
|
}
|
|
272
290
|
if (!response.ok) {
|
|
@@ -294,7 +312,7 @@ const getKeysFromRelayer = async (versionUrl, publicKeyId) => {
|
|
|
294
312
|
if (keyurlCache[versionUrl]) {
|
|
295
313
|
return keyurlCache[versionUrl];
|
|
296
314
|
}
|
|
297
|
-
const data = await
|
|
315
|
+
const data = await fetchRelayerV1Get('KEY_URL', `${versionUrl}/keyurl`);
|
|
298
316
|
try {
|
|
299
317
|
let pubKeyUrl;
|
|
300
318
|
// If no publicKeyId is provided, use the first one
|
|
@@ -383,7 +401,7 @@ class RelayerErrorBase extends Error {
|
|
|
383
401
|
_docsPath;
|
|
384
402
|
_docsUrl;
|
|
385
403
|
_version;
|
|
386
|
-
static VERSION =
|
|
404
|
+
static VERSION = version;
|
|
387
405
|
static DEFAULT_DOCS_BASE_URL = 'https//docs.zama.org';
|
|
388
406
|
static FULL_VERSION = `@zama-fhe/relayer-sdk@${RelayerErrorBase.VERSION}`;
|
|
389
407
|
constructor(params) {
|
|
@@ -792,6 +810,14 @@ function assertRecordStringArrayProperty(o, property, objName) {
|
|
|
792
810
|
}
|
|
793
811
|
}
|
|
794
812
|
}
|
|
813
|
+
function safeJSONstringify(o, space) {
|
|
814
|
+
try {
|
|
815
|
+
return JSON.stringify(o, (_, v) => (typeof v === 'bigint' ? v.toString() : v), space);
|
|
816
|
+
}
|
|
817
|
+
catch {
|
|
818
|
+
return '';
|
|
819
|
+
}
|
|
820
|
+
}
|
|
795
821
|
|
|
796
822
|
const abiKmsVerifier = [
|
|
797
823
|
'function getKmsSigners() view returns (address[])',
|
|
@@ -891,6 +917,7 @@ const getCoprocessorSignersThreshold = async (provider, inputVerifierContractAdd
|
|
|
891
917
|
return Number(threshold); // threshold is always supposed to fit in a number
|
|
892
918
|
};
|
|
893
919
|
|
|
920
|
+
// This file contains common utilities for both user and public decryption requests
|
|
894
921
|
const NumEncryptedBits = {
|
|
895
922
|
0: 2, // ebool
|
|
896
923
|
2: 8, // euint8
|
|
@@ -901,17 +928,17 @@ const NumEncryptedBits = {
|
|
|
901
928
|
7: 160, // eaddress
|
|
902
929
|
8: 256, // euint256
|
|
903
930
|
};
|
|
904
|
-
function getHandleType(handle) {
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
}
|
|
931
|
+
// export function getHandleType(handle: `0x${string}`): number {
|
|
932
|
+
// if (handle.length !== 66) {
|
|
933
|
+
// throw new Error(`Handle ${handle} is not of valid length`);
|
|
934
|
+
// }
|
|
935
|
+
// const hexPair = handle.slice(-4, -2).toLowerCase();
|
|
936
|
+
// const typeDiscriminant = parseInt(hexPair, 16);
|
|
937
|
+
// if (!(typeDiscriminant in NumEncryptedBits)) {
|
|
938
|
+
// throw new Error(`Handle ${handle} is not of valid type`);
|
|
939
|
+
// }
|
|
940
|
+
// return typeDiscriminant;
|
|
941
|
+
// }
|
|
915
942
|
function checkEncryptedBits(handles) {
|
|
916
943
|
let total = 0;
|
|
917
944
|
for (const handle of handles) {
|
|
@@ -969,7 +996,7 @@ function isBytes(value, bytewidth) {
|
|
|
969
996
|
if (!(value instanceof Uint8Array)) {
|
|
970
997
|
return false;
|
|
971
998
|
}
|
|
972
|
-
return value.length === bytewidth ;
|
|
999
|
+
return bytewidth ? value.length === bytewidth : true;
|
|
973
1000
|
}
|
|
974
1001
|
function isBytesHex(value, bytewidth) {
|
|
975
1002
|
if (!is0x(value)) {
|
|
@@ -1202,6 +1229,54 @@ function assertUint8ArrayProperty(o, property, objName) {
|
|
|
1202
1229
|
});
|
|
1203
1230
|
}
|
|
1204
1231
|
}
|
|
1232
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1233
|
+
// Hex
|
|
1234
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1235
|
+
const HEX_CHARS = {
|
|
1236
|
+
'0': 0,
|
|
1237
|
+
'1': 1,
|
|
1238
|
+
'2': 2,
|
|
1239
|
+
'3': 3,
|
|
1240
|
+
'4': 4,
|
|
1241
|
+
'5': 5,
|
|
1242
|
+
'6': 6,
|
|
1243
|
+
'7': 7,
|
|
1244
|
+
'8': 8,
|
|
1245
|
+
'9': 9,
|
|
1246
|
+
a: 10,
|
|
1247
|
+
b: 11,
|
|
1248
|
+
c: 12,
|
|
1249
|
+
d: 13,
|
|
1250
|
+
e: 14,
|
|
1251
|
+
f: 15,
|
|
1252
|
+
A: 10,
|
|
1253
|
+
B: 11,
|
|
1254
|
+
C: 12,
|
|
1255
|
+
D: 13,
|
|
1256
|
+
E: 14,
|
|
1257
|
+
F: 15,
|
|
1258
|
+
};
|
|
1259
|
+
Object.freeze(HEX_CHARS);
|
|
1260
|
+
const HEX_BYTES = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'));
|
|
1261
|
+
Object.freeze(HEX_BYTES);
|
|
1262
|
+
const HEX_CHARS_CODES = new Uint8Array([
|
|
1263
|
+
48,
|
|
1264
|
+
49,
|
|
1265
|
+
50,
|
|
1266
|
+
51,
|
|
1267
|
+
52,
|
|
1268
|
+
53,
|
|
1269
|
+
54,
|
|
1270
|
+
55,
|
|
1271
|
+
56,
|
|
1272
|
+
57, // '0'-'9'
|
|
1273
|
+
97,
|
|
1274
|
+
98,
|
|
1275
|
+
99,
|
|
1276
|
+
100,
|
|
1277
|
+
101,
|
|
1278
|
+
102, // 'a'-'f'
|
|
1279
|
+
]);
|
|
1205
1280
|
/**
|
|
1206
1281
|
* Convert a Uint8Array to a hex string (without 0x prefix).
|
|
1207
1282
|
*/
|
|
@@ -1221,15 +1296,49 @@ function bytesToHexNo0x(bytes) {
|
|
|
1221
1296
|
function bytesToHex(bytes) {
|
|
1222
1297
|
return `0x${bytesToHexNo0x(bytes)}`;
|
|
1223
1298
|
}
|
|
1299
|
+
function bytesToHexLarge(bytes) {
|
|
1300
|
+
const out = new Uint8Array(2 + bytes.length * 2);
|
|
1301
|
+
out[0] = 48; // '0'
|
|
1302
|
+
out[1] = 120; // 'x'
|
|
1303
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
1304
|
+
const j = 2 + i * 2;
|
|
1305
|
+
out[j] = HEX_CHARS_CODES[bytes[i] >> 4];
|
|
1306
|
+
out[j + 1] = HEX_CHARS_CODES[bytes[i] & 0xf];
|
|
1307
|
+
}
|
|
1308
|
+
return new TextDecoder().decode(out);
|
|
1309
|
+
}
|
|
1224
1310
|
/**
|
|
1225
1311
|
* Convert a hex string prefixed by 0x or not to a Uint8Array
|
|
1312
|
+
* Any invalid byte string is converted to 0
|
|
1313
|
+
* "0xzzff" = [0, 255]
|
|
1314
|
+
* "0xzfff" = [0, 255]
|
|
1226
1315
|
*/
|
|
1227
1316
|
function hexToBytes(hexString) {
|
|
1317
|
+
if (hexString.length % 2 !== 0) {
|
|
1318
|
+
throw new Error('Invalid hex string: odd length');
|
|
1319
|
+
}
|
|
1228
1320
|
const arr = hexString.replace(/^(0x)/, '').match(/.{1,2}/g);
|
|
1229
1321
|
if (!arr)
|
|
1230
1322
|
return new Uint8Array();
|
|
1231
1323
|
return Uint8Array.from(arr.map((byte) => parseInt(byte, 16)));
|
|
1232
1324
|
}
|
|
1325
|
+
function hexToBytesFaster(hexString, strict = false) {
|
|
1326
|
+
const offset = hexString[0] === '0' && hexString[1] === 'x' ? 2 : 0;
|
|
1327
|
+
const len = hexString.length - offset;
|
|
1328
|
+
if (len % 2 !== 0) {
|
|
1329
|
+
throw new Error('Invalid hex string: odd length');
|
|
1330
|
+
}
|
|
1331
|
+
const bytes = new Uint8Array(len / 2);
|
|
1332
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
1333
|
+
const hi = HEX_CHARS[hexString[offset + i * 2]];
|
|
1334
|
+
const lo = HEX_CHARS[hexString[offset + i * 2 + 1]];
|
|
1335
|
+
if ((hi === undefined || lo === undefined) && strict) {
|
|
1336
|
+
throw new Error(`Invalid hex character at position ${offset + i * 2}`);
|
|
1337
|
+
}
|
|
1338
|
+
bytes[i] = (hi << 4) | lo;
|
|
1339
|
+
}
|
|
1340
|
+
return bytes;
|
|
1341
|
+
}
|
|
1233
1342
|
/**
|
|
1234
1343
|
* Convert a Uint8Array to a bigint
|
|
1235
1344
|
*/
|
|
@@ -1243,9 +1352,6 @@ function bytesToBigInt(byteArray) {
|
|
|
1243
1352
|
}
|
|
1244
1353
|
return result;
|
|
1245
1354
|
}
|
|
1246
|
-
function toHexString(bytes, with0x = false) {
|
|
1247
|
-
return `${with0x ? '0x' : ''}${bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '')}`;
|
|
1248
|
-
}
|
|
1249
1355
|
async function fetchBytes(url) {
|
|
1250
1356
|
const response = await fetch(url);
|
|
1251
1357
|
if (!response.ok) {
|
|
@@ -1321,9 +1427,7 @@ function checkDeadlineValidity(startTimestamp, durationDays) {
|
|
|
1321
1427
|
throw Error('User decrypt request has expired');
|
|
1322
1428
|
}
|
|
1323
1429
|
}
|
|
1324
|
-
const userDecryptRequest = (kmsSigners, gatewayChainId, chainId, verifyingContractAddress, aclContractAddress,
|
|
1325
|
-
//relayerUrl: string,
|
|
1326
|
-
relayerProvider, provider, instanceOptions) => async (_handles, privateKey, publicKey, signature, contractAddresses, userAddress, startTimestamp, durationDays, options) => {
|
|
1430
|
+
const userDecryptRequest = (kmsSigners, gatewayChainId, chainId, verifyingContractAddress, aclContractAddress, relayerProvider, provider, defaultOptions) => async (_handles, privateKey, publicKey, signature, contractAddresses, userAddress, startTimestamp, durationDays, options) => {
|
|
1327
1431
|
const extraData = '0x00';
|
|
1328
1432
|
let pubKey;
|
|
1329
1433
|
let privKey;
|
|
@@ -1337,16 +1441,16 @@ relayerProvider, provider, instanceOptions) => async (_handles, privateKey, publ
|
|
|
1337
1441
|
// Casting handles if string
|
|
1338
1442
|
const signatureSanitized = signature.replace(/^(0x)/, '');
|
|
1339
1443
|
const publicKeySanitized = publicKey.replace(/^(0x)/, '');
|
|
1340
|
-
const
|
|
1444
|
+
const handleContractPairs = _handles.map((h) => ({
|
|
1341
1445
|
handle: typeof h.handle === 'string'
|
|
1342
|
-
?
|
|
1343
|
-
:
|
|
1446
|
+
? bytesToHex(hexToBytes(h.handle))
|
|
1447
|
+
: bytesToHex(h.handle),
|
|
1344
1448
|
contractAddress: getAddress$1(h.contractAddress),
|
|
1345
1449
|
}));
|
|
1346
|
-
checkEncryptedBits(
|
|
1450
|
+
checkEncryptedBits(handleContractPairs.map((h) => h.handle));
|
|
1347
1451
|
checkDeadlineValidity(BigInt(startTimestamp), BigInt(durationDays));
|
|
1348
|
-
const acl = new
|
|
1349
|
-
const verifications =
|
|
1452
|
+
const acl = new Contract(aclContractAddress, aclABI$1, provider);
|
|
1453
|
+
const verifications = handleContractPairs.map(async ({ handle, contractAddress }) => {
|
|
1350
1454
|
const userAllowed = await acl.persistAllowed(handle, userAddress);
|
|
1351
1455
|
const contractAllowed = await acl.persistAllowed(handle, contractAddress);
|
|
1352
1456
|
if (!userAllowed) {
|
|
@@ -1370,7 +1474,7 @@ relayerProvider, provider, instanceOptions) => async (_handles, privateKey, publ
|
|
|
1370
1474
|
throw e;
|
|
1371
1475
|
});
|
|
1372
1476
|
const payloadForRequest = {
|
|
1373
|
-
handleContractPairs
|
|
1477
|
+
handleContractPairs,
|
|
1374
1478
|
requestValidity: {
|
|
1375
1479
|
startTimestamp: startTimestamp.toString(), // Convert to string
|
|
1376
1480
|
durationDays: durationDays.toString(), // Convert to string
|
|
@@ -1382,13 +1486,10 @@ relayerProvider, provider, instanceOptions) => async (_handles, privateKey, publ
|
|
|
1382
1486
|
publicKey: publicKeySanitized,
|
|
1383
1487
|
extraData,
|
|
1384
1488
|
};
|
|
1385
|
-
const json = await relayerProvider.fetchPostUserDecrypt(payloadForRequest,
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
// payloadForRequest,
|
|
1390
|
-
// instanceOptions ?? options,
|
|
1391
|
-
// );
|
|
1489
|
+
const json = await relayerProvider.fetchPostUserDecrypt(payloadForRequest, {
|
|
1490
|
+
...defaultOptions,
|
|
1491
|
+
...options,
|
|
1492
|
+
});
|
|
1392
1493
|
// assume the KMS Signers have the correct order
|
|
1393
1494
|
let indexedKmsSigners = kmsSigners.map((signer, index) => {
|
|
1394
1495
|
return TKMS.new_server_id_addr(index + 1, signer);
|
|
@@ -1410,13 +1511,13 @@ relayerProvider, provider, instanceOptions) => async (_handles, privateKey, publ
|
|
|
1410
1511
|
signature: signatureSanitized,
|
|
1411
1512
|
client_address: userAddress,
|
|
1412
1513
|
enc_key: publicKeySanitized,
|
|
1413
|
-
ciphertext_handles:
|
|
1514
|
+
ciphertext_handles: handleContractPairs.map((h) => h.handle.replace(/^0x/, '')),
|
|
1414
1515
|
eip712_verifying_contract: verifyingContractAddress,
|
|
1415
1516
|
};
|
|
1416
1517
|
const decryption = TKMS.process_user_decryption_resp_from_js(client, payloadForVerification, eip712Domain, json, //json.response,
|
|
1417
1518
|
pubKey, privKey, true);
|
|
1418
1519
|
const listBigIntDecryptions = decryption.map((d) => bytesToBigInt(d.bytes));
|
|
1419
|
-
const results = buildUserDecryptResults(
|
|
1520
|
+
const results = buildUserDecryptResults(handleContractPairs.map((h) => h.handle), listBigIntDecryptions);
|
|
1420
1521
|
return results;
|
|
1421
1522
|
}
|
|
1422
1523
|
catch (e) {
|
|
@@ -1559,9 +1660,8 @@ const createEncryptedInput = ({ aclContractAddress, chainId, tfheCompactPublicKe
|
|
|
1559
1660
|
|
|
1560
1661
|
const MAX_UINT64 = BigInt('18446744073709551615'); // 2^64 - 1
|
|
1561
1662
|
BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff');
|
|
1562
|
-
const MAX_UINT32 = 0xffffffff;
|
|
1563
1663
|
const MAX_UINT8 = 0xff;
|
|
1564
|
-
function
|
|
1664
|
+
function numberToHexNo0x(num) {
|
|
1565
1665
|
let hex = num.toString(16);
|
|
1566
1666
|
return hex.length % 2 ? '0' + hex : hex;
|
|
1567
1667
|
}
|
|
@@ -1595,25 +1695,19 @@ function isUint8(value) {
|
|
|
1595
1695
|
}
|
|
1596
1696
|
return value <= MAX_UINT8;
|
|
1597
1697
|
}
|
|
1598
|
-
function isUint32(value) {
|
|
1599
|
-
if (!isUint(value)) {
|
|
1600
|
-
return false;
|
|
1601
|
-
}
|
|
1602
|
-
return value <= MAX_UINT32;
|
|
1603
|
-
}
|
|
1604
1698
|
function isUint64(value) {
|
|
1605
1699
|
if (!isUint(value)) {
|
|
1606
1700
|
return false;
|
|
1607
1701
|
}
|
|
1608
1702
|
return value <= MAX_UINT64;
|
|
1609
1703
|
}
|
|
1610
|
-
function
|
|
1611
|
-
if (!
|
|
1612
|
-
throw new InvalidTypeError({ expectedType: '
|
|
1704
|
+
function numberToBytes32(num) {
|
|
1705
|
+
if (!isUintNumber(num)) {
|
|
1706
|
+
throw new InvalidTypeError({ expectedType: 'Uint' });
|
|
1613
1707
|
}
|
|
1614
1708
|
const buffer = new ArrayBuffer(32);
|
|
1615
1709
|
const view = new DataView(buffer);
|
|
1616
|
-
view.
|
|
1710
|
+
view.setBigUint64(24, BigInt(num), false);
|
|
1617
1711
|
return new Uint8Array(buffer);
|
|
1618
1712
|
}
|
|
1619
1713
|
function assertIsUint8(value) {
|
|
@@ -1708,47 +1802,216 @@ function checksummedAddressToBytes20(address) {
|
|
|
1708
1802
|
return bytes;
|
|
1709
1803
|
}
|
|
1710
1804
|
|
|
1805
|
+
class FhevmHandleError extends RelayerErrorBase {
|
|
1806
|
+
constructor({ handle, message }) {
|
|
1807
|
+
super({
|
|
1808
|
+
message: message ??
|
|
1809
|
+
(handle
|
|
1810
|
+
? `FHEVM Handle "${handle}" is invalid.`
|
|
1811
|
+
: `FHEVM Handle is invalid.`),
|
|
1812
|
+
name: 'FhevmHandleError',
|
|
1813
|
+
});
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1817
|
+
class FheTypeError extends RelayerErrorBase {
|
|
1818
|
+
constructor({ fheTypeId, message, }) {
|
|
1819
|
+
super({
|
|
1820
|
+
message: message ??
|
|
1821
|
+
(fheTypeId
|
|
1822
|
+
? `FheTypeId "${fheTypeId}" is invalid.`
|
|
1823
|
+
: `FheTypeId is invalid.`),
|
|
1824
|
+
name: 'FheTypeError',
|
|
1825
|
+
});
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
|
|
1829
|
+
const FheTypeIdToName = {
|
|
1830
|
+
0: 'ebool',
|
|
1831
|
+
//1: 'euint4', has been deprecated
|
|
1832
|
+
2: 'euint8',
|
|
1833
|
+
3: 'euint16',
|
|
1834
|
+
4: 'euint32',
|
|
1835
|
+
5: 'euint64',
|
|
1836
|
+
6: 'euint128',
|
|
1837
|
+
7: 'eaddress',
|
|
1838
|
+
8: 'euint256',
|
|
1839
|
+
};
|
|
1840
|
+
const FheTypeIdToEncryptionBitwidth = {
|
|
1841
|
+
0: 2,
|
|
1842
|
+
//1:?, euint4 has been deprecated
|
|
1843
|
+
2: 8,
|
|
1844
|
+
3: 16,
|
|
1845
|
+
4: 32,
|
|
1846
|
+
5: 64,
|
|
1847
|
+
6: 128,
|
|
1848
|
+
7: 160,
|
|
1849
|
+
8: 256,
|
|
1850
|
+
};
|
|
1851
|
+
const EncryptionBitwidthToFheTypeId = {
|
|
1852
|
+
2: 0,
|
|
1853
|
+
//?:1, euint4 has been deprecated
|
|
1854
|
+
8: 2,
|
|
1855
|
+
16: 3,
|
|
1856
|
+
32: 4,
|
|
1857
|
+
64: 5,
|
|
1858
|
+
128: 6,
|
|
1859
|
+
160: 7,
|
|
1860
|
+
256: 8,
|
|
1861
|
+
};
|
|
1862
|
+
const FheTypeIdToSolidityPrimitiveTypeName = {
|
|
1863
|
+
0: 'bool',
|
|
1864
|
+
//1:'uint256', euint4 has been deprecated
|
|
1865
|
+
2: 'uint256',
|
|
1866
|
+
3: 'uint256',
|
|
1867
|
+
4: 'uint256',
|
|
1868
|
+
5: 'uint256',
|
|
1869
|
+
6: 'uint256',
|
|
1870
|
+
7: 'address',
|
|
1871
|
+
8: 'uint256',
|
|
1872
|
+
};
|
|
1873
|
+
Object.freeze(FheTypeIdToEncryptionBitwidth);
|
|
1874
|
+
Object.freeze(EncryptionBitwidthToFheTypeId);
|
|
1875
|
+
Object.freeze(FheTypeIdToSolidityPrimitiveTypeName);
|
|
1876
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1877
|
+
// Type Guards
|
|
1878
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1879
|
+
/**
|
|
1880
|
+
* Checks if a value is a valid FheTypeId.
|
|
1881
|
+
* @example isFheTypeId(2) // true (euint8)
|
|
1882
|
+
* @example isFheTypeId(1) // false (euint4 is deprecated)
|
|
1883
|
+
*/
|
|
1884
|
+
function isFheTypeId(value) {
|
|
1885
|
+
switch (value) {
|
|
1886
|
+
case 0:
|
|
1887
|
+
// 1: euint4 is deprecated
|
|
1888
|
+
case 2:
|
|
1889
|
+
case 3:
|
|
1890
|
+
case 4:
|
|
1891
|
+
case 5:
|
|
1892
|
+
case 6:
|
|
1893
|
+
case 7:
|
|
1894
|
+
case 8:
|
|
1895
|
+
return true;
|
|
1896
|
+
default:
|
|
1897
|
+
return false;
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
/**
|
|
1901
|
+
* Checks if a value is a valid encryption bit width.
|
|
1902
|
+
* @example isEncryptionBits(8) // true
|
|
1903
|
+
* @example isEncryptionBits(4) // false (euint4 is deprecated)
|
|
1904
|
+
*/
|
|
1905
|
+
function isEncryptionBits(value) {
|
|
1906
|
+
if (typeof value !== 'number') {
|
|
1907
|
+
return false;
|
|
1908
|
+
}
|
|
1909
|
+
return value in EncryptionBitwidthToFheTypeId;
|
|
1910
|
+
}
|
|
1911
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1912
|
+
// FheTypeId extractors
|
|
1913
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1914
|
+
/**
|
|
1915
|
+
* Converts an encryption bit width to its corresponding FheTypeId.
|
|
1916
|
+
* @throws {FheTypeError} If bitwidth is not a valid encryption bit width.
|
|
1917
|
+
* @example fheTypeIdFromEncryptionBits(8) // 2 (euint8)
|
|
1918
|
+
*/
|
|
1919
|
+
function fheTypeIdFromEncryptionBits(bitwidth) {
|
|
1920
|
+
if (!isEncryptionBits(bitwidth)) {
|
|
1921
|
+
throw new FheTypeError({
|
|
1922
|
+
message: `Invalid encryption bits ${bitwidth}`,
|
|
1923
|
+
});
|
|
1924
|
+
}
|
|
1925
|
+
return EncryptionBitwidthToFheTypeId[bitwidth];
|
|
1926
|
+
}
|
|
1927
|
+
/**
|
|
1928
|
+
* Converts an FheTypeId to its corresponding FheTypeName.
|
|
1929
|
+
* @throws {FheTypeError} If id is not a valid FheTypeId.
|
|
1930
|
+
* @example fheTypeNameFromId(2) // 'euint8'
|
|
1931
|
+
*/
|
|
1932
|
+
function fheTypeNameFromId(id) {
|
|
1933
|
+
if (!isFheTypeId(id)) {
|
|
1934
|
+
throw new FheTypeError({
|
|
1935
|
+
message: `Invalid FheType id '${id}'`,
|
|
1936
|
+
});
|
|
1937
|
+
}
|
|
1938
|
+
return FheTypeIdToName[id];
|
|
1939
|
+
}
|
|
1940
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1941
|
+
// Solidity primitive type names
|
|
1942
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1943
|
+
/**
|
|
1944
|
+
* Returns the Solidity primitive type name for an FheTypeId.
|
|
1945
|
+
* @example solidityPrimitiveTypeNameFromFheTypeId(0) // 'bool'
|
|
1946
|
+
* @example solidityPrimitiveTypeNameFromFheTypeId(7) // 'address'
|
|
1947
|
+
* @example solidityPrimitiveTypeNameFromFheTypeId(2) // 'uint256'
|
|
1948
|
+
*/
|
|
1949
|
+
function solidityPrimitiveTypeNameFromFheTypeId(typeId) {
|
|
1950
|
+
if (!isFheTypeId(typeId)) {
|
|
1951
|
+
throw new FheTypeError({
|
|
1952
|
+
message: `Invalid FheType id '${typeId}'`,
|
|
1953
|
+
});
|
|
1954
|
+
}
|
|
1955
|
+
return FheTypeIdToSolidityPrimitiveTypeName[typeId];
|
|
1956
|
+
}
|
|
1957
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1958
|
+
// Encryption Bits
|
|
1959
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1960
|
+
/**
|
|
1961
|
+
* Returns the encryption bit width for an FheTypeId.
|
|
1962
|
+
* @example encryptionBitsFromFheTypeId(2) // 8 (euint8)
|
|
1963
|
+
* @example encryptionBitsFromFheTypeId(7) // 160 (eaddress)
|
|
1964
|
+
*/
|
|
1965
|
+
function encryptionBitsFromFheTypeId(typeId) {
|
|
1966
|
+
if (!isFheTypeId(typeId)) {
|
|
1967
|
+
throw new FheTypeError({
|
|
1968
|
+
message: `Invalid FheType id '${typeId}'`,
|
|
1969
|
+
});
|
|
1970
|
+
}
|
|
1971
|
+
return FheTypeIdToEncryptionBitwidth[typeId];
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1711
1974
|
////////////////////////////////////////////////////////////////////////////////
|
|
1712
1975
|
// FhevmHandle
|
|
1713
1976
|
////////////////////////////////////////////////////////////////////////////////
|
|
1714
1977
|
class FhevmHandle {
|
|
1978
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
1979
|
+
// Instance Properties
|
|
1980
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
1715
1981
|
_hash21;
|
|
1716
1982
|
_chainId;
|
|
1717
1983
|
_fheTypeId;
|
|
1718
1984
|
_version;
|
|
1719
1985
|
_computed;
|
|
1720
1986
|
_index;
|
|
1987
|
+
_handleBytes32Hex;
|
|
1988
|
+
_handleBytes32;
|
|
1989
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
1990
|
+
// Static Constants
|
|
1991
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
1721
1992
|
static RAW_CT_HASH_DOMAIN_SEPARATOR = 'ZK-w_rct';
|
|
1722
1993
|
static HANDLE_HASH_DOMAIN_SEPARATOR = 'ZK-w_hdl';
|
|
1723
|
-
static
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
static FheTypeEncryptionBitwidthsToId = {
|
|
1734
|
-
2: 0,
|
|
1735
|
-
8: 2,
|
|
1736
|
-
16: 3,
|
|
1737
|
-
32: 4,
|
|
1738
|
-
64: 5,
|
|
1739
|
-
128: 6,
|
|
1740
|
-
160: 7,
|
|
1741
|
-
256: 8,
|
|
1742
|
-
};
|
|
1743
|
-
static {
|
|
1744
|
-
Object.freeze(FhevmHandle.FheTypeIdToEncryptionBitwidths);
|
|
1745
|
-
Object.freeze(FhevmHandle.FheTypeEncryptionBitwidthsToId);
|
|
1746
|
-
}
|
|
1747
|
-
constructor(hash21, chainId, fheTypeId, version, computed, index) {
|
|
1994
|
+
static CURRENT_CIPHERTEXT_VERSION = 0;
|
|
1995
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
1996
|
+
// Constructor
|
|
1997
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
1998
|
+
constructor({ hash21, chainId, fheTypeId, version, computed, index, handleBytes32, handleBytes32Hex, }) {
|
|
1999
|
+
if (!isUintNumber(chainId)) {
|
|
2000
|
+
throw new FhevmHandleError({
|
|
2001
|
+
message: 'ChainId must be a positive integer',
|
|
2002
|
+
});
|
|
2003
|
+
}
|
|
1748
2004
|
if (BigInt(chainId) > MAX_UINT64) {
|
|
1749
2005
|
// fhevm assumes chainID is only taking up to 8 bytes
|
|
1750
|
-
throw new
|
|
2006
|
+
throw new FhevmHandleError({
|
|
2007
|
+
message: 'ChainId exceeds maximum allowed value (8 bytes)',
|
|
2008
|
+
});
|
|
1751
2009
|
}
|
|
2010
|
+
if (!isBytesHex(hash21, 21)) {
|
|
2011
|
+
throw new FhevmHandleError({ message: 'Hash21 should be 21 bytes long' });
|
|
2012
|
+
}
|
|
2013
|
+
this._handleBytes32 = handleBytes32;
|
|
2014
|
+
this._handleBytes32Hex = handleBytes32Hex;
|
|
1752
2015
|
this._hash21 = hash21;
|
|
1753
2016
|
this._chainId = chainId;
|
|
1754
2017
|
this._fheTypeId = fheTypeId;
|
|
@@ -1758,6 +2021,9 @@ class FhevmHandle {
|
|
|
1758
2021
|
this._index = index;
|
|
1759
2022
|
}
|
|
1760
2023
|
}
|
|
2024
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2025
|
+
// Instance Getters
|
|
2026
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
1761
2027
|
get hash21() {
|
|
1762
2028
|
return this._hash21;
|
|
1763
2029
|
}
|
|
@@ -1767,6 +2033,9 @@ class FhevmHandle {
|
|
|
1767
2033
|
get fheTypeId() {
|
|
1768
2034
|
return this._fheTypeId;
|
|
1769
2035
|
}
|
|
2036
|
+
get fheTypeName() {
|
|
2037
|
+
return fheTypeNameFromId(this._fheTypeId);
|
|
2038
|
+
}
|
|
1770
2039
|
get version() {
|
|
1771
2040
|
return this._version;
|
|
1772
2041
|
}
|
|
@@ -1776,6 +2045,106 @@ class FhevmHandle {
|
|
|
1776
2045
|
get index() {
|
|
1777
2046
|
return this._index;
|
|
1778
2047
|
}
|
|
2048
|
+
get encryptedBitwidth() {
|
|
2049
|
+
return encryptionBitsFromFheTypeId(this._fheTypeId);
|
|
2050
|
+
}
|
|
2051
|
+
get solidityPrimitiveTypeName() {
|
|
2052
|
+
return solidityPrimitiveTypeNameFromFheTypeId(this._fheTypeId);
|
|
2053
|
+
}
|
|
2054
|
+
toJSON() {
|
|
2055
|
+
return {
|
|
2056
|
+
handle: this.toBytes32Hex(),
|
|
2057
|
+
fheTypeName: this.fheTypeName,
|
|
2058
|
+
fheTypeId: this.fheTypeId,
|
|
2059
|
+
chainId: this.chainId,
|
|
2060
|
+
index: this.index,
|
|
2061
|
+
computed: this.computed,
|
|
2062
|
+
encryptedBitwidth: this.encryptedBitwidth,
|
|
2063
|
+
version: this.version,
|
|
2064
|
+
solidityPrimitiveTypeName: this.solidityPrimitiveTypeName,
|
|
2065
|
+
hash21: this.hash21,
|
|
2066
|
+
};
|
|
2067
|
+
}
|
|
2068
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2069
|
+
// Instance Serialization
|
|
2070
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2071
|
+
toBytes32() {
|
|
2072
|
+
if (this._handleBytes32 === undefined) {
|
|
2073
|
+
assertRelayer((this._index === undefined && this._computed) ||
|
|
2074
|
+
(this._index !== undefined && this._index < 255 && !this._computed));
|
|
2075
|
+
const chainId32Bytes = numberToBytes32(this._chainId);
|
|
2076
|
+
const chainId8Bytes = chainId32Bytes.subarray(24, 32);
|
|
2077
|
+
const handleHash21 = hexToBytes(this._hash21);
|
|
2078
|
+
assertRelayer(handleHash21.length === 21);
|
|
2079
|
+
const handleBytes32AsBytes = new Uint8Array(32);
|
|
2080
|
+
handleBytes32AsBytes.set(handleHash21, 0);
|
|
2081
|
+
handleBytes32AsBytes[21] = this._index === undefined ? 255 : this._index;
|
|
2082
|
+
handleBytes32AsBytes.set(chainId8Bytes, 22);
|
|
2083
|
+
handleBytes32AsBytes[30] = this._fheTypeId;
|
|
2084
|
+
handleBytes32AsBytes[31] = this._version;
|
|
2085
|
+
this._handleBytes32 = handleBytes32AsBytes;
|
|
2086
|
+
}
|
|
2087
|
+
return this._handleBytes32;
|
|
2088
|
+
}
|
|
2089
|
+
toBytes32Hex() {
|
|
2090
|
+
if (this._handleBytes32Hex === undefined) {
|
|
2091
|
+
this._handleBytes32Hex = bytesToHex(this.toBytes32());
|
|
2092
|
+
}
|
|
2093
|
+
return this._handleBytes32Hex;
|
|
2094
|
+
}
|
|
2095
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2096
|
+
// Static Factory Methods
|
|
2097
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2098
|
+
static fromComponents(params) {
|
|
2099
|
+
return new FhevmHandle(params);
|
|
2100
|
+
}
|
|
2101
|
+
static fromBytes32(handle) {
|
|
2102
|
+
if (!isBytes32(handle)) {
|
|
2103
|
+
throw new FhevmHandleError({
|
|
2104
|
+
message: `FHEVM Handle is not a valid bytes32 array.`,
|
|
2105
|
+
});
|
|
2106
|
+
}
|
|
2107
|
+
const bytes = handle;
|
|
2108
|
+
// Extract hash21 (bytes 0-20)
|
|
2109
|
+
const hash21 = bytesToHex(bytes.slice(0, 21));
|
|
2110
|
+
// Extract index (byte 21) - 255 means computed
|
|
2111
|
+
const indexByte = bytes[21];
|
|
2112
|
+
const computed = indexByte === 255;
|
|
2113
|
+
const index = computed ? undefined : indexByte;
|
|
2114
|
+
// Extract chainId (bytes 22-29, 8 bytes as big-endian uint64)
|
|
2115
|
+
let chainId = 0;
|
|
2116
|
+
for (let i = 22; i < 30; i++) {
|
|
2117
|
+
chainId = chainId * 256 + bytes[i];
|
|
2118
|
+
}
|
|
2119
|
+
// Extract fheTypeId (byte 30)
|
|
2120
|
+
const fheTypeIdByte = bytes[30];
|
|
2121
|
+
if (!isFheTypeId(fheTypeIdByte)) {
|
|
2122
|
+
throw new FhevmHandleError({
|
|
2123
|
+
handle,
|
|
2124
|
+
message: `FHEVM Handle "${handle}" is invalid. Unknown FheType: ${fheTypeIdByte}`,
|
|
2125
|
+
});
|
|
2126
|
+
}
|
|
2127
|
+
// Extract version (byte 31)
|
|
2128
|
+
const version = bytes[31];
|
|
2129
|
+
return new FhevmHandle({
|
|
2130
|
+
hash21,
|
|
2131
|
+
chainId,
|
|
2132
|
+
fheTypeId: fheTypeIdByte,
|
|
2133
|
+
version,
|
|
2134
|
+
computed,
|
|
2135
|
+
index,
|
|
2136
|
+
handleBytes32: handle,
|
|
2137
|
+
});
|
|
2138
|
+
}
|
|
2139
|
+
static fromBytes32Hex(handle) {
|
|
2140
|
+
if (!isBytes32Hex(handle)) {
|
|
2141
|
+
throw new FhevmHandleError({ handle });
|
|
2142
|
+
}
|
|
2143
|
+
const bytes = hexToBytes(handle);
|
|
2144
|
+
const h = FhevmHandle.fromBytes32(bytes);
|
|
2145
|
+
h._handleBytes32Hex = handle;
|
|
2146
|
+
return h;
|
|
2147
|
+
}
|
|
1779
2148
|
static fromZKProof(params) {
|
|
1780
2149
|
assertIsChecksummedAddress(params.aclAddress);
|
|
1781
2150
|
assertIsUint64(params.chainId);
|
|
@@ -1785,7 +2154,7 @@ class FhevmHandle {
|
|
|
1785
2154
|
fheTypeIds = params.fheTypeIds;
|
|
1786
2155
|
}
|
|
1787
2156
|
else if (params.fheTypeEncryptionBitwidths !== undefined) {
|
|
1788
|
-
fheTypeIds = params.fheTypeEncryptionBitwidths.map((w) =>
|
|
2157
|
+
fheTypeIds = params.fheTypeEncryptionBitwidths.map((w) => fheTypeIdFromEncryptionBits(w));
|
|
1789
2158
|
}
|
|
1790
2159
|
else {
|
|
1791
2160
|
throw new InternalError({
|
|
@@ -1816,22 +2185,69 @@ class FhevmHandle {
|
|
|
1816
2185
|
const handles = [];
|
|
1817
2186
|
for (let i = 0; i < fheTypeIds.length; ++i) {
|
|
1818
2187
|
const hash21 = FhevmHandle._computeInputHash21(hexToBytes(blobHashBytes32Hex), params.aclAddress, params.chainId, i);
|
|
1819
|
-
handles.push(new FhevmHandle(
|
|
2188
|
+
handles.push(new FhevmHandle({
|
|
2189
|
+
hash21,
|
|
2190
|
+
chainId: params.chainId,
|
|
2191
|
+
fheTypeId: fheTypeIds[i],
|
|
2192
|
+
version: params.ciphertextVersion,
|
|
2193
|
+
computed: false,
|
|
2194
|
+
index: i,
|
|
2195
|
+
}));
|
|
1820
2196
|
}
|
|
1821
2197
|
return handles;
|
|
1822
2198
|
}
|
|
2199
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2200
|
+
// Static Parsing
|
|
2201
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2202
|
+
static parse(handle) {
|
|
2203
|
+
if (isBytes(handle)) {
|
|
2204
|
+
return FhevmHandle.fromBytes32(handle);
|
|
2205
|
+
}
|
|
2206
|
+
return FhevmHandle.fromBytes32Hex(handle);
|
|
2207
|
+
}
|
|
2208
|
+
static canParse(handle) {
|
|
2209
|
+
try {
|
|
2210
|
+
FhevmHandle.parse(handle);
|
|
2211
|
+
return true;
|
|
2212
|
+
}
|
|
2213
|
+
catch {
|
|
2214
|
+
return false;
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
2217
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2218
|
+
// Static Assertions
|
|
2219
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2220
|
+
static assertIsHandleHex(handle) {
|
|
2221
|
+
if (typeof handle !== 'string') {
|
|
2222
|
+
throw new FhevmHandleError({
|
|
2223
|
+
message: 'Invalid bytes32 hexadecimal string',
|
|
2224
|
+
});
|
|
2225
|
+
}
|
|
2226
|
+
if (!FhevmHandle.canParse(handle)) {
|
|
2227
|
+
throw new FhevmHandleError({ handle });
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2231
|
+
// Static Helpers
|
|
2232
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2233
|
+
static currentCiphertextVersion() {
|
|
2234
|
+
return FhevmHandle.CURRENT_CIPHERTEXT_VERSION;
|
|
2235
|
+
}
|
|
2236
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2237
|
+
// Private Helpers
|
|
2238
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
1823
2239
|
/**
|
|
1824
2240
|
* blobHashBytes32 = keccak256(ciphertextWithZKProof)
|
|
1825
2241
|
*/
|
|
1826
2242
|
static _computeInputHash21(blobHashBytes32, aclAddress, chainId, index) {
|
|
1827
2243
|
/*
|
|
1828
2244
|
https://github.com/zama-ai/fhevm/blob/8ffbd5906ab3d57af178e049930e3fc065c9d4b3/coprocessor/fhevm-engine/zkproof-worker/src/verifier.rs#L431C7-L431C8
|
|
1829
|
-
|
|
2245
|
+
|
|
1830
2246
|
handle_hash = Bytes("ZK-w_hdl") + blobHash 32 Bytes + index 1 Byte + aclAddress 20 Bytes + chainId 32 bytes
|
|
1831
2247
|
===========================================================================================================
|
|
1832
2248
|
|
|
1833
2249
|
const HANDLE_HASH_DOMAIN_SEPARATOR: [u8; 8] = *b"ZK-w_hdl";
|
|
1834
|
-
|
|
2250
|
+
|
|
1835
2251
|
let mut handle_hash = Keccak256::new();
|
|
1836
2252
|
handle_hash.update(HANDLE_HASH_DOMAIN_SEPARATOR);
|
|
1837
2253
|
handle_hash.update(blob_hash);
|
|
@@ -1852,27 +2268,12 @@ class FhevmHandle {
|
|
|
1852
2268
|
assertIsUint64(chainId);
|
|
1853
2269
|
const encryptionIndexByte1 = new Uint8Array([index]);
|
|
1854
2270
|
const aclContractAddressBytes20 = checksummedAddressToBytes20(aclAddress);
|
|
1855
|
-
const chainIdBytes32 =
|
|
2271
|
+
const chainIdBytes32 = numberToBytes32(chainId);
|
|
1856
2272
|
const encoder = new TextEncoder();
|
|
1857
2273
|
const domainSepBytes = encoder.encode(FhevmHandle.HANDLE_HASH_DOMAIN_SEPARATOR);
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
assertRelayer((this._index === undefined && this._computed) ||
|
|
1862
|
-
(this._index !== undefined && this._index < 255 && !this._computed));
|
|
1863
|
-
const chainId32Bytes = uint32ToBytes32(this._chainId);
|
|
1864
|
-
const chainId8Bytes = chainId32Bytes.subarray(24, 32);
|
|
1865
|
-
const handleHash = hexToBytes(this._hash21);
|
|
1866
|
-
const handleBytes32AsBytes = new Uint8Array(32);
|
|
1867
|
-
handleBytes32AsBytes.set(handleHash, 0);
|
|
1868
|
-
handleBytes32AsBytes[21] = this._index === undefined ? 255 : this._index;
|
|
1869
|
-
handleBytes32AsBytes.set(chainId8Bytes, 22);
|
|
1870
|
-
handleBytes32AsBytes[30] = this._fheTypeId;
|
|
1871
|
-
handleBytes32AsBytes[31] = this._version;
|
|
1872
|
-
return handleBytes32AsBytes;
|
|
1873
|
-
}
|
|
1874
|
-
toBytes32Hex() {
|
|
1875
|
-
return bytesToHex(this.toBytes32());
|
|
2274
|
+
const hashBytes32Hex = keccak256(concatBytes(domainSepBytes, blobHashBytes32, encryptionIndexByte1, aclContractAddressBytes20, chainIdBytes32));
|
|
2275
|
+
// Truncate to 21 bytes (0x + 42 hex chars)
|
|
2276
|
+
return hashBytes32Hex.slice(0, 2 + 2 * 21);
|
|
1876
2277
|
}
|
|
1877
2278
|
}
|
|
1878
2279
|
|
|
@@ -1881,6 +2282,89 @@ const getAddress = (value) => getAddress$2(value);
|
|
|
1881
2282
|
const currentCiphertextVersion = () => {
|
|
1882
2283
|
return 0;
|
|
1883
2284
|
};
|
|
2285
|
+
async function requestCiphertextWithZKProofVerification({ bits, ciphertext, contractAddress, userAddress, aclContractAddress, verifyingContractAddressInputVerification, chainId, gatewayChainId, relayerProvider, coprocessorSigners, thresholdCoprocessorSigners, extraData, options, }) {
|
|
2286
|
+
const payload = {
|
|
2287
|
+
contractAddress,
|
|
2288
|
+
userAddress,
|
|
2289
|
+
ciphertextWithInputVerification: bytesToHexNo0x(ciphertext),
|
|
2290
|
+
contractChainId: ('0x' + chainId.toString(16)),
|
|
2291
|
+
extraData,
|
|
2292
|
+
};
|
|
2293
|
+
const json = await relayerProvider.fetchPostInputProof(payload, options);
|
|
2294
|
+
if (!isFhevmRelayerInputProofResponse(json)) {
|
|
2295
|
+
throwRelayerInternalError('INPUT_PROOF', json);
|
|
2296
|
+
}
|
|
2297
|
+
const fhevmHandles = FhevmHandle.fromZKProof({
|
|
2298
|
+
ciphertextWithZKProof: ciphertext,
|
|
2299
|
+
chainId,
|
|
2300
|
+
aclAddress: aclContractAddress,
|
|
2301
|
+
ciphertextVersion: currentCiphertextVersion(),
|
|
2302
|
+
fheTypeEncryptionBitwidths: bits,
|
|
2303
|
+
});
|
|
2304
|
+
const handles = fhevmHandles.map((h) => h.toBytes32());
|
|
2305
|
+
const result = json;
|
|
2306
|
+
// Note that the hex strings returned by the relayer do have have the 0x prefix
|
|
2307
|
+
if (result.handles && result.handles.length > 0) {
|
|
2308
|
+
const responseHandles = result.handles.map(hexToBytes);
|
|
2309
|
+
if (handles.length != responseHandles.length) {
|
|
2310
|
+
throw new Error(`Incorrect Handles list sizes: (expected) ${handles.length} != ${responseHandles.length} (received)`);
|
|
2311
|
+
}
|
|
2312
|
+
for (let index = 0; index < handles.length; index += 1) {
|
|
2313
|
+
let handle = handles[index];
|
|
2314
|
+
let responseHandle = responseHandles[index];
|
|
2315
|
+
let expected = bytesToHexNo0x(handle);
|
|
2316
|
+
let current = bytesToHexNo0x(responseHandle);
|
|
2317
|
+
if (expected !== current) {
|
|
2318
|
+
throw new Error(`Incorrect Handle ${index}: (expected) ${expected} != ${current} (received)`);
|
|
2319
|
+
}
|
|
2320
|
+
}
|
|
2321
|
+
}
|
|
2322
|
+
const signatures = result.signatures;
|
|
2323
|
+
// verify signatures for inputs:
|
|
2324
|
+
const domain = {
|
|
2325
|
+
name: 'InputVerification',
|
|
2326
|
+
version: '1',
|
|
2327
|
+
chainId: gatewayChainId,
|
|
2328
|
+
verifyingContract: verifyingContractAddressInputVerification,
|
|
2329
|
+
};
|
|
2330
|
+
const types = {
|
|
2331
|
+
CiphertextVerification: [
|
|
2332
|
+
{ name: 'ctHandles', type: 'bytes32[]' },
|
|
2333
|
+
{ name: 'userAddress', type: 'address' },
|
|
2334
|
+
{ name: 'contractAddress', type: 'address' },
|
|
2335
|
+
{ name: 'contractChainId', type: 'uint256' },
|
|
2336
|
+
{ name: 'extraData', type: 'bytes' },
|
|
2337
|
+
],
|
|
2338
|
+
};
|
|
2339
|
+
const recoveredAddresses = signatures.map((signature) => {
|
|
2340
|
+
const sig = signature.startsWith('0x') ? signature : `0x${signature}`;
|
|
2341
|
+
const recoveredAddress = ethers.verifyTypedData(domain, types, {
|
|
2342
|
+
ctHandles: handles,
|
|
2343
|
+
userAddress,
|
|
2344
|
+
contractAddress,
|
|
2345
|
+
contractChainId: chainId,
|
|
2346
|
+
extraData,
|
|
2347
|
+
}, sig);
|
|
2348
|
+
return recoveredAddress;
|
|
2349
|
+
});
|
|
2350
|
+
const thresholdReached = isThresholdReached$1(coprocessorSigners, recoveredAddresses, thresholdCoprocessorSigners);
|
|
2351
|
+
if (!thresholdReached) {
|
|
2352
|
+
throw Error('Coprocessor signers threshold is not reached');
|
|
2353
|
+
}
|
|
2354
|
+
// inputProof is len(list_handles) + numCoprocessorSigners + list_handles + signatureCoprocessorSigners (1+1+NUM_HANDLES*32+65*numSigners)
|
|
2355
|
+
let inputProof = numberToHexNo0x(handles.length);
|
|
2356
|
+
const numSigners = signatures.length;
|
|
2357
|
+
inputProof += numberToHexNo0x(numSigners);
|
|
2358
|
+
const listHandlesStr = handles.map((i) => bytesToHexNo0x(i));
|
|
2359
|
+
listHandlesStr.map((handle) => (inputProof += handle));
|
|
2360
|
+
signatures.map((signature) => (inputProof += signature.slice(2))); // removes the '0x' prefix from the `signature` string
|
|
2361
|
+
// Append the extra data to the input proof
|
|
2362
|
+
inputProof += extraData.slice(2);
|
|
2363
|
+
return {
|
|
2364
|
+
handles,
|
|
2365
|
+
inputProof: hexToBytes(inputProof),
|
|
2366
|
+
};
|
|
2367
|
+
}
|
|
1884
2368
|
function isThresholdReached$1(coprocessorSigners, recoveredAddresses, threshold) {
|
|
1885
2369
|
const addressMap = new Map();
|
|
1886
2370
|
recoveredAddresses.forEach((address, index) => {
|
|
@@ -1912,9 +2396,7 @@ function isFhevmRelayerInputProofResponse(json) {
|
|
|
1912
2396
|
return (response.signatures.every((s) => typeof s === 'string') &&
|
|
1913
2397
|
response.handles.every((h) => typeof h === 'string'));
|
|
1914
2398
|
}
|
|
1915
|
-
const createRelayerEncryptedInput = (aclContractAddress, verifyingContractAddressInputVerification, chainId, gatewayChainId,
|
|
1916
|
-
//relayerUrl: string,
|
|
1917
|
-
relayerProvider, tfheCompactPublicKey, publicParams, coprocessorSigners, thresholdCoprocessorSigners, instanceOptions) => (contractAddress, userAddress) => {
|
|
2399
|
+
const createRelayerEncryptedInput = (aclContractAddress, verifyingContractAddressInputVerification, chainId, gatewayChainId, relayerProvider, tfheCompactPublicKey, publicParams, coprocessorSigners, thresholdCoprocessorSigners, defaultOptions) => (contractAddress, userAddress) => {
|
|
1918
2400
|
if (!isAddress$1(contractAddress)) {
|
|
1919
2401
|
throw new Error('Contract address is not a valid address.');
|
|
1920
2402
|
}
|
|
@@ -1966,25 +2448,31 @@ relayerProvider, tfheCompactPublicKey, publicParams, coprocessorSigners, thresho
|
|
|
1966
2448
|
getBits() {
|
|
1967
2449
|
return input.getBits();
|
|
1968
2450
|
},
|
|
2451
|
+
generateZKProof() {
|
|
2452
|
+
return {
|
|
2453
|
+
chainId,
|
|
2454
|
+
aclContractAddress: aclContractAddress,
|
|
2455
|
+
userAddress: userAddress,
|
|
2456
|
+
contractAddress: contractAddress,
|
|
2457
|
+
ciphertextWithZkProof: input.encrypt(),
|
|
2458
|
+
bits: input.getBits(),
|
|
2459
|
+
};
|
|
2460
|
+
},
|
|
1969
2461
|
encrypt: async (options) => {
|
|
1970
2462
|
const extraData = '0x00';
|
|
1971
2463
|
const bits = input.getBits();
|
|
1972
2464
|
const ciphertext = input.encrypt();
|
|
1973
|
-
//console.log(`ciphertext=${toHexString(ciphertext)}`);
|
|
1974
2465
|
const payload = {
|
|
1975
2466
|
contractAddress: getAddress(contractAddress),
|
|
1976
2467
|
userAddress: getAddress(userAddress),
|
|
1977
|
-
ciphertextWithInputVerification:
|
|
2468
|
+
ciphertextWithInputVerification: bytesToHexNo0x(ciphertext),
|
|
1978
2469
|
contractChainId: ('0x' + chainId.toString(16)),
|
|
1979
2470
|
extraData,
|
|
1980
2471
|
};
|
|
1981
|
-
const json = await relayerProvider.fetchPostInputProof(payload,
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
// payload,
|
|
1986
|
-
// options ?? instanceOptions,
|
|
1987
|
-
// );
|
|
2472
|
+
const json = await relayerProvider.fetchPostInputProof(payload, {
|
|
2473
|
+
...defaultOptions,
|
|
2474
|
+
...options,
|
|
2475
|
+
});
|
|
1988
2476
|
if (!isFhevmRelayerInputProofResponse(json)) {
|
|
1989
2477
|
throwRelayerInternalError('INPUT_PROOF', json);
|
|
1990
2478
|
}
|
|
@@ -1996,7 +2484,6 @@ relayerProvider, tfheCompactPublicKey, publicParams, coprocessorSigners, thresho
|
|
|
1996
2484
|
fheTypeEncryptionBitwidths: bits,
|
|
1997
2485
|
});
|
|
1998
2486
|
const handles = fhevmHandles.map((h) => h.toBytes32());
|
|
1999
|
-
//const result = json.response;
|
|
2000
2487
|
const result = json;
|
|
2001
2488
|
// Note that the hex strings returned by the relayer do have have the 0x prefix
|
|
2002
2489
|
if (result.handles && result.handles.length > 0) {
|
|
@@ -2007,8 +2494,8 @@ relayerProvider, tfheCompactPublicKey, publicParams, coprocessorSigners, thresho
|
|
|
2007
2494
|
for (let index = 0; index < handles.length; index += 1) {
|
|
2008
2495
|
let handle = handles[index];
|
|
2009
2496
|
let responseHandle = responseHandles[index];
|
|
2010
|
-
let expected =
|
|
2011
|
-
let current =
|
|
2497
|
+
let expected = bytesToHexNo0x(handle);
|
|
2498
|
+
let current = bytesToHexNo0x(responseHandle);
|
|
2012
2499
|
if (expected !== current) {
|
|
2013
2500
|
throw new Error(`Incorrect Handle ${index}: (expected) ${expected} != ${current} (received)`);
|
|
2014
2501
|
}
|
|
@@ -2047,10 +2534,10 @@ relayerProvider, tfheCompactPublicKey, publicParams, coprocessorSigners, thresho
|
|
|
2047
2534
|
throw Error('Coprocessor signers threshold is not reached');
|
|
2048
2535
|
}
|
|
2049
2536
|
// inputProof is len(list_handles) + numCoprocessorSigners + list_handles + signatureCoprocessorSigners (1+1+NUM_HANDLES*32+65*numSigners)
|
|
2050
|
-
let inputProof =
|
|
2537
|
+
let inputProof = numberToHexNo0x(handles.length);
|
|
2051
2538
|
const numSigners = signatures.length;
|
|
2052
|
-
inputProof +=
|
|
2053
|
-
const listHandlesStr = handles.map((i) =>
|
|
2539
|
+
inputProof += numberToHexNo0x(numSigners);
|
|
2540
|
+
const listHandlesStr = handles.map((i) => bytesToHexNo0x(i));
|
|
2054
2541
|
listHandlesStr.map((handle) => (inputProof += handle));
|
|
2055
2542
|
signatures.map((signature) => (inputProof += signature.slice(2))); // removes the '0x' prefix from the `signature` string
|
|
2056
2543
|
// Append the extra data to the input proof
|
|
@@ -2063,15 +2550,30 @@ relayerProvider, tfheCompactPublicKey, publicParams, coprocessorSigners, thresho
|
|
|
2063
2550
|
};
|
|
2064
2551
|
};
|
|
2065
2552
|
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
const
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2553
|
+
function ensureError(e) {
|
|
2554
|
+
if (e instanceof Error) {
|
|
2555
|
+
return e;
|
|
2556
|
+
}
|
|
2557
|
+
const message = e.message ?? 'Non-Error value caught in exception handler';
|
|
2558
|
+
const name = e.name ?? 'ErrorWrapper';
|
|
2559
|
+
const cause = e.cause ?? e;
|
|
2560
|
+
const err = new Error(message, { cause });
|
|
2561
|
+
err.name = name;
|
|
2562
|
+
return err;
|
|
2563
|
+
}
|
|
2564
|
+
function assertNever(value, message) {
|
|
2565
|
+
throw new InternalError({ message });
|
|
2566
|
+
}
|
|
2567
|
+
|
|
2568
|
+
const aclABI = [
|
|
2569
|
+
'function isAllowedForDecryption(bytes32 handle) view returns (bool)',
|
|
2570
|
+
];
|
|
2571
|
+
function isThresholdReached(kmsSigners, recoveredAddresses, threshold) {
|
|
2572
|
+
const addressMap = new Map();
|
|
2573
|
+
recoveredAddresses.forEach((address, index) => {
|
|
2574
|
+
if (addressMap.has(address)) {
|
|
2575
|
+
const duplicateValue = address;
|
|
2576
|
+
throw new Error(`Duplicate KMS signer address found: ${duplicateValue} appears multiple times in recovered addresses`);
|
|
2075
2577
|
}
|
|
2076
2578
|
addressMap.set(address, index);
|
|
2077
2579
|
});
|
|
@@ -2088,7 +2590,7 @@ function abiEncodeClearValues(clearValues) {
|
|
|
2088
2590
|
const abiValues = [];
|
|
2089
2591
|
for (let i = 0; i < handlesBytes32Hex.length; ++i) {
|
|
2090
2592
|
const handle = handlesBytes32Hex[i];
|
|
2091
|
-
const handleType =
|
|
2593
|
+
const handleType = FhevmHandle.parse(handle).fheTypeId;
|
|
2092
2594
|
let clearTextValue = clearValues[handle];
|
|
2093
2595
|
if (typeof clearTextValue === 'boolean') {
|
|
2094
2596
|
clearTextValue = clearTextValue ? '0x01' : '0x00';
|
|
@@ -2125,7 +2627,7 @@ function abiEncodeClearValues(clearValues) {
|
|
|
2125
2627
|
break;
|
|
2126
2628
|
}
|
|
2127
2629
|
default: {
|
|
2128
|
-
|
|
2630
|
+
assertNever(handleType, `Unsupported Fhevm primitive type id: ${handleType}`);
|
|
2129
2631
|
}
|
|
2130
2632
|
}
|
|
2131
2633
|
}
|
|
@@ -2150,50 +2652,38 @@ function buildDecryptionProof(kmsSignatures, extraData) {
|
|
|
2150
2652
|
]);
|
|
2151
2653
|
return decryptionProof;
|
|
2152
2654
|
}
|
|
2153
|
-
const CiphertextType = {
|
|
2154
|
-
0: 'bool',
|
|
2155
|
-
2: 'uint256',
|
|
2156
|
-
3: 'uint256',
|
|
2157
|
-
4: 'uint256',
|
|
2158
|
-
5: 'uint256',
|
|
2159
|
-
6: 'uint256',
|
|
2160
|
-
7: 'address',
|
|
2161
|
-
8: 'uint256',
|
|
2162
|
-
};
|
|
2163
2655
|
function deserializeClearValues(handles, decryptedResult) {
|
|
2164
|
-
let
|
|
2656
|
+
let fheTypeIdList = [];
|
|
2165
2657
|
for (const handle of handles) {
|
|
2166
|
-
const
|
|
2167
|
-
|
|
2168
|
-
typesList.push(typeDiscriminant);
|
|
2658
|
+
const typeDiscriminant = FhevmHandle.parse(handle).fheTypeId;
|
|
2659
|
+
fheTypeIdList.push(typeDiscriminant);
|
|
2169
2660
|
}
|
|
2170
2661
|
const restoredEncoded = '0x' +
|
|
2171
2662
|
'00'.repeat(32) + // dummy requestID (ignored)
|
|
2172
2663
|
decryptedResult.slice(2) +
|
|
2173
2664
|
'00'.repeat(32); // dummy empty bytes[] length (ignored)
|
|
2174
|
-
const abiTypes =
|
|
2175
|
-
const abiType =
|
|
2665
|
+
const abiTypes = fheTypeIdList.map((t) => {
|
|
2666
|
+
const abiType = solidityPrimitiveTypeNameFromFheTypeId(t); // all types are valid because this was supposedly checked already inside the `checkEncryptedBits` function
|
|
2176
2667
|
return abiType;
|
|
2177
2668
|
});
|
|
2178
2669
|
const coder = new AbiCoder();
|
|
2179
2670
|
const decoded = coder.decode(['uint256', ...abiTypes, 'bytes[]'], restoredEncoded);
|
|
2180
2671
|
// strip dummy first/last element
|
|
2181
|
-
const rawValues = decoded.slice(1, 1 +
|
|
2672
|
+
const rawValues = decoded.slice(1, 1 + fheTypeIdList.length);
|
|
2182
2673
|
const results = {};
|
|
2183
2674
|
handles.forEach((handle, idx) => (results[handle] = rawValues[idx]));
|
|
2184
2675
|
return results;
|
|
2185
2676
|
}
|
|
2186
|
-
const publicDecryptRequest = (kmsSigners, thresholdSigners, gatewayChainId, verifyingContractAddress, aclContractAddress,
|
|
2187
|
-
//relayerUrl: string,
|
|
2188
|
-
relayerProvider, provider, instanceOptions) => async (_handles, options) => {
|
|
2677
|
+
const publicDecryptRequest = (kmsSigners, thresholdSigners, gatewayChainId, verifyingContractAddress, aclContractAddress, relayerProvider, provider, defaultOptions) => async (_handles, options) => {
|
|
2189
2678
|
const extraData = '0x00';
|
|
2190
2679
|
const acl = new ethers.Contract(aclContractAddress, aclABI, provider);
|
|
2680
|
+
// This will be replaced by new sanitize classes
|
|
2191
2681
|
let handles;
|
|
2192
2682
|
try {
|
|
2193
2683
|
handles = await Promise.all(_handles.map(async (_handle) => {
|
|
2194
2684
|
const handle = typeof _handle === 'string'
|
|
2195
|
-
?
|
|
2196
|
-
:
|
|
2685
|
+
? bytesToHex(hexToBytes(_handle))
|
|
2686
|
+
: bytesToHex(_handle);
|
|
2197
2687
|
const isAllowedForDecryption = await acl.isAllowedForDecryption(handle);
|
|
2198
2688
|
if (!isAllowedForDecryption) {
|
|
2199
2689
|
throw new Error(`Handle ${handle} is not allowed for public decryption!`);
|
|
@@ -2210,13 +2700,10 @@ relayerProvider, provider, instanceOptions) => async (_handles, options) => {
|
|
|
2210
2700
|
ciphertextHandles: handles,
|
|
2211
2701
|
extraData,
|
|
2212
2702
|
};
|
|
2213
|
-
const json = await relayerProvider.fetchPostPublicDecrypt(payloadForRequest,
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
// payloadForRequest,
|
|
2218
|
-
// options ?? instanceOptions,
|
|
2219
|
-
// );
|
|
2703
|
+
const json = await relayerProvider.fetchPostPublicDecrypt(payloadForRequest, {
|
|
2704
|
+
...defaultOptions,
|
|
2705
|
+
...options,
|
|
2706
|
+
});
|
|
2220
2707
|
// verify signatures on decryption:
|
|
2221
2708
|
const domain = {
|
|
2222
2709
|
name: 'Decryption',
|
|
@@ -2354,8 +2841,8 @@ const createEIP712 = (verifyingContract, contractsChainId) => (publicKey, contra
|
|
|
2354
2841
|
const generateKeypair = () => {
|
|
2355
2842
|
const keypair = TKMS.ml_kem_pke_keygen();
|
|
2356
2843
|
return {
|
|
2357
|
-
publicKey:
|
|
2358
|
-
privateKey:
|
|
2844
|
+
publicKey: bytesToHexNo0x(TKMS.ml_kem_pke_pk_to_u8vec(TKMS.ml_kem_pke_get_pk(keypair))),
|
|
2845
|
+
privateKey: bytesToHexNo0x(TKMS.ml_kem_pke_sk_to_u8vec(keypair)),
|
|
2359
2846
|
};
|
|
2360
2847
|
};
|
|
2361
2848
|
|
|
@@ -2412,7 +2899,7 @@ class RelayerV1Provider extends AbstractRelayerProvider {
|
|
|
2412
2899
|
return 1;
|
|
2413
2900
|
}
|
|
2414
2901
|
async fetchGetKeyUrl() {
|
|
2415
|
-
const response = await
|
|
2902
|
+
const response = await fetchRelayerV1Get('KEY_URL', this.keyUrl);
|
|
2416
2903
|
return response;
|
|
2417
2904
|
}
|
|
2418
2905
|
async fetchPostInputProof(payload, options) {
|
|
@@ -2430,12 +2917,12 @@ class RelayerV1Provider extends AbstractRelayerProvider {
|
|
|
2430
2917
|
}
|
|
2431
2918
|
}
|
|
2432
2919
|
*/
|
|
2433
|
-
const json = await
|
|
2920
|
+
const json = await fetchRelayerV1Post('INPUT_PROOF', this.inputProof, payload, options);
|
|
2434
2921
|
assertIsRelayerInputProofResult(json.response, 'fetchPostInputProof()');
|
|
2435
2922
|
return json.response;
|
|
2436
2923
|
}
|
|
2437
2924
|
async fetchPostPublicDecrypt(payload, options) {
|
|
2438
|
-
const json = await
|
|
2925
|
+
const json = await fetchRelayerV1Post('PUBLIC_DECRYPT', this.publicDecrypt, payload, options);
|
|
2439
2926
|
const response = json.response[0];
|
|
2440
2927
|
const result = {
|
|
2441
2928
|
signatures: response.signatures,
|
|
@@ -2446,24 +2933,12 @@ class RelayerV1Provider extends AbstractRelayerProvider {
|
|
|
2446
2933
|
return result;
|
|
2447
2934
|
}
|
|
2448
2935
|
async fetchPostUserDecrypt(payload, options) {
|
|
2449
|
-
const json = await
|
|
2936
|
+
const json = await fetchRelayerV1Post('USER_DECRYPT', this.userDecrypt, payload, options);
|
|
2450
2937
|
assertIsRelayerUserDecryptResult(json.response, 'RelayerUserDecryptResult()');
|
|
2451
2938
|
return json.response;
|
|
2452
2939
|
}
|
|
2453
2940
|
}
|
|
2454
2941
|
|
|
2455
|
-
function ensureError(e) {
|
|
2456
|
-
if (e instanceof Error) {
|
|
2457
|
-
return e;
|
|
2458
|
-
}
|
|
2459
|
-
const message = e.message ?? 'Non-Error value caught in exception handler';
|
|
2460
|
-
const name = e.name ?? 'ErrorWrapper';
|
|
2461
|
-
const cause = e.cause ?? e;
|
|
2462
|
-
const err = new Error(message, { cause });
|
|
2463
|
-
err.name = name;
|
|
2464
|
-
return err;
|
|
2465
|
-
}
|
|
2466
|
-
|
|
2467
2942
|
class RelayerV2ProviderError extends RelayerErrorBase {
|
|
2468
2943
|
_operation;
|
|
2469
2944
|
constructor(params) {
|
|
@@ -2940,22 +3415,6 @@ class RelayerV2RequestInternalError extends RelayerV2RequestErrorBase {
|
|
|
2940
3415
|
}
|
|
2941
3416
|
}
|
|
2942
3417
|
|
|
2943
|
-
function assertIsRelayerV2ResultQueued(value, name) {
|
|
2944
|
-
assertRecordStringProperty(value, 'jobId', name);
|
|
2945
|
-
}
|
|
2946
|
-
|
|
2947
|
-
/*
|
|
2948
|
-
type RelayerV2ResponseQueued = {
|
|
2949
|
-
status: "queued";
|
|
2950
|
-
result: RelayerV2ResultQueued;
|
|
2951
|
-
}
|
|
2952
|
-
*/
|
|
2953
|
-
function assertIsRelayerV2ResponseQueued(value, name) {
|
|
2954
|
-
assertRecordStringProperty(value, 'status', name, 'queued');
|
|
2955
|
-
assertNonNullableRecordProperty(value, 'result', name);
|
|
2956
|
-
assertIsRelayerV2ResultQueued(value.result, `${name}.result`);
|
|
2957
|
-
}
|
|
2958
|
-
|
|
2959
3418
|
class RelayerV2ResponseApiError extends RelayerV2ResponseErrorBase {
|
|
2960
3419
|
constructor(params) {
|
|
2961
3420
|
super({
|
|
@@ -3017,7 +3476,58 @@ class RelayerV2MaxRetryError extends RelayerV2FetchErrorBase {
|
|
|
3017
3476
|
}
|
|
3018
3477
|
}
|
|
3019
3478
|
|
|
3479
|
+
function assertIsRelayerV2PostResultQueued(value, name) {
|
|
3480
|
+
assertRecordStringProperty(value, 'jobId', name);
|
|
3481
|
+
}
|
|
3482
|
+
|
|
3483
|
+
/*
|
|
3484
|
+
{
|
|
3485
|
+
status: 'queued';
|
|
3486
|
+
requestId: string;
|
|
3487
|
+
result: {
|
|
3488
|
+
jobId: string;
|
|
3489
|
+
};
|
|
3490
|
+
}
|
|
3491
|
+
*/
|
|
3492
|
+
function assertIsRelayerV2PostResponseQueued(value, name) {
|
|
3493
|
+
assertRecordStringProperty(value, 'status', name, 'queued');
|
|
3494
|
+
assertRecordStringProperty(value, 'requestId', name);
|
|
3495
|
+
assertNonNullableRecordProperty(value, 'result', name);
|
|
3496
|
+
assertIsRelayerV2PostResultQueued(value.result, `${name}.result`);
|
|
3497
|
+
}
|
|
3498
|
+
/*
|
|
3499
|
+
{
|
|
3500
|
+
status: 'queued';
|
|
3501
|
+
requestId: string;
|
|
3502
|
+
}
|
|
3503
|
+
*/
|
|
3504
|
+
function assertIsRelayerV2GetResponseQueued(value, name) {
|
|
3505
|
+
assertRecordStringProperty(value, 'status', name, 'queued');
|
|
3506
|
+
assertRecordStringProperty(value, 'requestId', name);
|
|
3507
|
+
}
|
|
3508
|
+
|
|
3509
|
+
class RelayerV2TimeoutError extends RelayerV2RequestErrorBase {
|
|
3510
|
+
constructor(params) {
|
|
3511
|
+
super({
|
|
3512
|
+
...params,
|
|
3513
|
+
name: 'RelayerV2TimeoutError',
|
|
3514
|
+
message: `Request timed out after ${params.timeoutMs}ms`,
|
|
3515
|
+
});
|
|
3516
|
+
}
|
|
3517
|
+
}
|
|
3518
|
+
|
|
3519
|
+
class RelayerV2AbortError extends RelayerV2RequestErrorBase {
|
|
3520
|
+
constructor(params) {
|
|
3521
|
+
super({
|
|
3522
|
+
...params,
|
|
3523
|
+
name: 'RelayerV2AbortError',
|
|
3524
|
+
message: `Request aborted`,
|
|
3525
|
+
});
|
|
3526
|
+
}
|
|
3527
|
+
}
|
|
3528
|
+
|
|
3020
3529
|
class RelayerV2AsyncRequest {
|
|
3530
|
+
_fetchMethod;
|
|
3021
3531
|
_jobId;
|
|
3022
3532
|
_jobIdTimestamp;
|
|
3023
3533
|
_state;
|
|
@@ -3032,17 +3542,18 @@ class RelayerV2AsyncRequest {
|
|
|
3032
3542
|
_retryAfterTimeoutID;
|
|
3033
3543
|
_url;
|
|
3034
3544
|
_payload;
|
|
3035
|
-
|
|
3545
|
+
_fhevmAuth;
|
|
3036
3546
|
_retryAfterTimeoutPromiseFuncReject;
|
|
3037
3547
|
_onProgress;
|
|
3038
|
-
|
|
3548
|
+
_requestMaxDurationInMs;
|
|
3039
3549
|
_requestStartTimestamp;
|
|
3040
3550
|
_requestGlobalTimeoutID;
|
|
3041
3551
|
_throwErrorIfNoRetryAfter;
|
|
3042
|
-
static
|
|
3043
|
-
static
|
|
3044
|
-
static
|
|
3045
|
-
static
|
|
3552
|
+
static DEFAULT_RETRY_AFTER_MS = 2500;
|
|
3553
|
+
static MINIMUM_RETRY_AFTER_MS = 1000;
|
|
3554
|
+
static DEFAULT_GLOBAL_REQUEST_TIMEOUT_MS = 60 * 60 * 1000; // 1 hour
|
|
3555
|
+
static MAX_GET_RETRY = 60 * 30; // number of default retries in 1 hour (30 retries/min)
|
|
3556
|
+
static MAX_POST_RETRY = RelayerV2AsyncRequest.MAX_GET_RETRY;
|
|
3046
3557
|
constructor(params) {
|
|
3047
3558
|
if (params.relayerOperation !== 'INPUT_PROOF' &&
|
|
3048
3559
|
params.relayerOperation !== 'PUBLIC_DECRYPT' &&
|
|
@@ -3059,14 +3570,14 @@ class RelayerV2AsyncRequest {
|
|
|
3059
3570
|
this._internalAbortController = new AbortController();
|
|
3060
3571
|
this._internalAbortSignal = this._internalAbortController.signal;
|
|
3061
3572
|
this._internalAbortSignal.addEventListener('abort', this._handleInternalSignalAbort);
|
|
3062
|
-
this._externalAbortSignal = params.signal;
|
|
3573
|
+
this._externalAbortSignal = params.options?.signal;
|
|
3063
3574
|
if (this._externalAbortSignal) {
|
|
3064
3575
|
this._externalAbortSignal.addEventListener('abort', this._handleExternalSignalAbort);
|
|
3065
3576
|
}
|
|
3066
3577
|
this._url = params.url;
|
|
3067
3578
|
this._payload = params.payload;
|
|
3068
|
-
this.
|
|
3069
|
-
this._onProgress = params.onProgress;
|
|
3579
|
+
this._fhevmAuth = params.options?.auth;
|
|
3580
|
+
this._onProgress = params.options?.onProgress;
|
|
3070
3581
|
this._state = {
|
|
3071
3582
|
aborted: false,
|
|
3072
3583
|
canceled: false,
|
|
@@ -3075,6 +3586,7 @@ class RelayerV2AsyncRequest {
|
|
|
3075
3586
|
running: false,
|
|
3076
3587
|
succeeded: false,
|
|
3077
3588
|
terminated: false,
|
|
3589
|
+
timeout: false,
|
|
3078
3590
|
};
|
|
3079
3591
|
this._retryCount = 0;
|
|
3080
3592
|
this._retryAfterTimeoutID = undefined;
|
|
@@ -3082,9 +3594,9 @@ class RelayerV2AsyncRequest {
|
|
|
3082
3594
|
this._terminateReason = undefined;
|
|
3083
3595
|
this._publicAPINoReentrancy = false;
|
|
3084
3596
|
this._throwErrorIfNoRetryAfter = params.throwErrorIfNoRetryAfter ?? false;
|
|
3085
|
-
this.
|
|
3086
|
-
params.
|
|
3087
|
-
RelayerV2AsyncRequest.
|
|
3597
|
+
this._requestMaxDurationInMs =
|
|
3598
|
+
params.options?.timeout ??
|
|
3599
|
+
RelayerV2AsyncRequest.DEFAULT_GLOBAL_REQUEST_TIMEOUT_MS;
|
|
3088
3600
|
}
|
|
3089
3601
|
//////////////////////////////////////////////////////////////////////////////
|
|
3090
3602
|
// Public API: run
|
|
@@ -3126,6 +3638,12 @@ class RelayerV2AsyncRequest {
|
|
|
3126
3638
|
state: { ...this._state },
|
|
3127
3639
|
});
|
|
3128
3640
|
}
|
|
3641
|
+
if (this._state.timeout) {
|
|
3642
|
+
throw new RelayerV2StateError({
|
|
3643
|
+
message: `Relayer.run() failed. Request already timeout.`,
|
|
3644
|
+
state: { ...this._state },
|
|
3645
|
+
});
|
|
3646
|
+
}
|
|
3129
3647
|
if (this._externalAbortSignal?.aborted === true) {
|
|
3130
3648
|
throw new RelayerV2StateError({
|
|
3131
3649
|
message: `Relayer.run() failed. External AbortSignal already aborted (reason:${this._externalAbortSignal?.reason}).`,
|
|
@@ -3146,7 +3664,7 @@ class RelayerV2AsyncRequest {
|
|
|
3146
3664
|
}
|
|
3147
3665
|
this._state.running = true;
|
|
3148
3666
|
this._requestStartTimestamp = Date.now();
|
|
3149
|
-
this._setGlobalRequestTimeout(this.
|
|
3667
|
+
this._setGlobalRequestTimeout(this._requestMaxDurationInMs);
|
|
3150
3668
|
try {
|
|
3151
3669
|
const json = await this._runPostLoop();
|
|
3152
3670
|
this._state.succeeded = true;
|
|
@@ -3217,6 +3735,12 @@ class RelayerV2AsyncRequest {
|
|
|
3217
3735
|
get failed() {
|
|
3218
3736
|
return this._state.failed;
|
|
3219
3737
|
}
|
|
3738
|
+
get aborted() {
|
|
3739
|
+
return this._state.aborted;
|
|
3740
|
+
}
|
|
3741
|
+
get timeout() {
|
|
3742
|
+
return this._state.timeout;
|
|
3743
|
+
}
|
|
3220
3744
|
get succeeded() {
|
|
3221
3745
|
return this._state.succeeded;
|
|
3222
3746
|
}
|
|
@@ -3237,6 +3761,8 @@ class RelayerV2AsyncRequest {
|
|
|
3237
3761
|
//////////////////////////////////////////////////////////////////////////////
|
|
3238
3762
|
// POST : 202 | 400 | 429 | 500 | 503
|
|
3239
3763
|
async _runPostLoop() {
|
|
3764
|
+
this._assert(this._fetchMethod === undefined, 'this._fetchMethod === undefined');
|
|
3765
|
+
this._fetchMethod = 'POST';
|
|
3240
3766
|
// No infinite loop!
|
|
3241
3767
|
let i = 0;
|
|
3242
3768
|
while (i < RelayerV2AsyncRequest.MAX_POST_RETRY) {
|
|
@@ -3261,19 +3787,18 @@ class RelayerV2AsyncRequest {
|
|
|
3261
3787
|
// - SyntaxError: Expected property name or '}' in JSON at position 1 (line 1 column 2) at JSON.parse (<anonymous>)
|
|
3262
3788
|
const bodyJson = await this._getResponseJson(response);
|
|
3263
3789
|
try {
|
|
3264
|
-
|
|
3790
|
+
assertIsRelayerV2PostResponseQueued(bodyJson, 'body');
|
|
3265
3791
|
}
|
|
3266
3792
|
catch (cause) {
|
|
3267
|
-
this.
|
|
3793
|
+
this._throwResponseInvalidBodyError({
|
|
3268
3794
|
fetchMethod: 'POST',
|
|
3269
3795
|
status: responseStatus,
|
|
3270
3796
|
cause: cause,
|
|
3271
3797
|
elapsed,
|
|
3798
|
+
bodyJson: safeJSONstringify(bodyJson),
|
|
3272
3799
|
});
|
|
3273
3800
|
}
|
|
3274
|
-
|
|
3275
|
-
if (retry_after_sec < 1)
|
|
3276
|
-
retry_after_sec = 1;
|
|
3801
|
+
const retryAfterMs = this._getRetryAfterHeaderValueInMs(response);
|
|
3277
3802
|
// Debug: will throw an assert failed error if jobId has already been set
|
|
3278
3803
|
this._setJobIdOnce(bodyJson.result.jobId);
|
|
3279
3804
|
// Async onProgress callback
|
|
@@ -3286,11 +3811,10 @@ class RelayerV2AsyncRequest {
|
|
|
3286
3811
|
jobId: this.jobId,
|
|
3287
3812
|
operation: this._relayerOperation,
|
|
3288
3813
|
retryCount: this._retryCount,
|
|
3289
|
-
|
|
3814
|
+
retryAfterMs,
|
|
3290
3815
|
elapsed,
|
|
3291
3816
|
});
|
|
3292
|
-
|
|
3293
|
-
await this._setRetryAfterTimeout(retry_after_sec * 1000);
|
|
3817
|
+
await this._setRetryAfterTimeout(retryAfterMs);
|
|
3294
3818
|
const json = await this._runGetLoop();
|
|
3295
3819
|
return json;
|
|
3296
3820
|
}
|
|
@@ -3303,11 +3827,12 @@ class RelayerV2AsyncRequest {
|
|
|
3303
3827
|
assertIsRelayerV2ResponseFailedWithError400(bodyJson, 'body');
|
|
3304
3828
|
}
|
|
3305
3829
|
catch (cause) {
|
|
3306
|
-
this.
|
|
3830
|
+
this._throwResponseInvalidBodyError({
|
|
3307
3831
|
fetchMethod: 'POST',
|
|
3308
3832
|
status: responseStatus,
|
|
3309
3833
|
cause: cause,
|
|
3310
3834
|
elapsed,
|
|
3835
|
+
bodyJson: safeJSONstringify(bodyJson),
|
|
3311
3836
|
});
|
|
3312
3837
|
}
|
|
3313
3838
|
this._throwRelayerV2ResponseApiError({
|
|
@@ -3327,29 +3852,28 @@ class RelayerV2AsyncRequest {
|
|
|
3327
3852
|
assertIsRelayerV2ResponseFailedWithError429(bodyJson, 'body');
|
|
3328
3853
|
}
|
|
3329
3854
|
catch (cause) {
|
|
3330
|
-
this.
|
|
3855
|
+
this._throwResponseInvalidBodyError({
|
|
3331
3856
|
fetchMethod: 'POST',
|
|
3332
3857
|
status: responseStatus,
|
|
3333
3858
|
cause: cause,
|
|
3334
3859
|
elapsed,
|
|
3860
|
+
bodyJson: safeJSONstringify(bodyJson),
|
|
3335
3861
|
});
|
|
3336
3862
|
}
|
|
3337
|
-
|
|
3338
|
-
if (retry_after_sec < 1)
|
|
3339
|
-
retry_after_sec = 1;
|
|
3863
|
+
const retryAfterMs = this._getRetryAfterHeaderValueInMs(response);
|
|
3340
3864
|
// Async onProgress callback
|
|
3341
3865
|
this._postAsyncOnProgressCallback({
|
|
3342
3866
|
type: 'ratelimited',
|
|
3343
3867
|
url: this._url,
|
|
3344
3868
|
method: 'POST',
|
|
3345
3869
|
status: responseStatus,
|
|
3346
|
-
|
|
3870
|
+
retryAfterMs,
|
|
3347
3871
|
retryCount: this._retryCount,
|
|
3348
3872
|
elapsed,
|
|
3349
|
-
|
|
3873
|
+
relayerApiError: bodyJson.error,
|
|
3350
3874
|
});
|
|
3351
3875
|
// Wait if needed (minimum 1s)
|
|
3352
|
-
await this._setRetryAfterTimeout(
|
|
3876
|
+
await this._setRetryAfterTimeout(retryAfterMs);
|
|
3353
3877
|
continue;
|
|
3354
3878
|
}
|
|
3355
3879
|
// RelayerV2ResponseFailed
|
|
@@ -3362,11 +3886,12 @@ class RelayerV2AsyncRequest {
|
|
|
3362
3886
|
assertIsRelayerV2ResponseFailedWithError500(bodyJson, 'body');
|
|
3363
3887
|
}
|
|
3364
3888
|
catch (cause) {
|
|
3365
|
-
this.
|
|
3889
|
+
this._throwResponseInvalidBodyError({
|
|
3366
3890
|
fetchMethod: 'POST',
|
|
3367
3891
|
status: responseStatus,
|
|
3368
3892
|
cause: cause,
|
|
3369
3893
|
elapsed,
|
|
3894
|
+
bodyJson: safeJSONstringify(bodyJson),
|
|
3370
3895
|
});
|
|
3371
3896
|
}
|
|
3372
3897
|
this._throwRelayerV2ResponseApiError({
|
|
@@ -3386,11 +3911,12 @@ class RelayerV2AsyncRequest {
|
|
|
3386
3911
|
assertIsRelayerV2ResponseFailedWithError503(bodyJson, 'body');
|
|
3387
3912
|
}
|
|
3388
3913
|
catch (cause) {
|
|
3389
|
-
this.
|
|
3914
|
+
this._throwResponseInvalidBodyError({
|
|
3390
3915
|
fetchMethod: 'POST',
|
|
3391
3916
|
status: responseStatus,
|
|
3392
3917
|
cause: cause,
|
|
3393
3918
|
elapsed,
|
|
3919
|
+
bodyJson: safeJSONstringify(bodyJson),
|
|
3394
3920
|
});
|
|
3395
3921
|
}
|
|
3396
3922
|
this._throwRelayerV2ResponseApiError({
|
|
@@ -3426,8 +3952,10 @@ class RelayerV2AsyncRequest {
|
|
|
3426
3952
|
// GET: 200 | 202 | 404 | 500 | 503 | 504
|
|
3427
3953
|
// GET is not rate-limited, therefore there is not 429 error
|
|
3428
3954
|
async _runGetLoop() {
|
|
3955
|
+
this._assert(this._fetchMethod === 'POST', "this._fetchMethod === 'POST'");
|
|
3429
3956
|
this._assert(this._jobId !== undefined, 'this._jobId !== undefined');
|
|
3430
3957
|
this._assert(this._jobIdTimestamp !== undefined, 'this._jobIdTimestamp !== undefined');
|
|
3958
|
+
this._fetchMethod = 'GET';
|
|
3431
3959
|
let i = 0;
|
|
3432
3960
|
while (i < RelayerV2AsyncRequest.MAX_GET_RETRY) {
|
|
3433
3961
|
++i;
|
|
@@ -3514,6 +4042,7 @@ class RelayerV2AsyncRequest {
|
|
|
3514
4042
|
status: responseStatus,
|
|
3515
4043
|
elapsed,
|
|
3516
4044
|
cause: cause,
|
|
4045
|
+
bodyJson: safeJSONstringify(bodyJson),
|
|
3517
4046
|
});
|
|
3518
4047
|
}
|
|
3519
4048
|
// RelayerV2ResultPublicDecrypt
|
|
@@ -3525,7 +4054,7 @@ class RelayerV2AsyncRequest {
|
|
|
3525
4054
|
case 202: {
|
|
3526
4055
|
const bodyJson = await this._getResponseJson(response);
|
|
3527
4056
|
try {
|
|
3528
|
-
|
|
4057
|
+
assertIsRelayerV2GetResponseQueued(bodyJson, 'body');
|
|
3529
4058
|
}
|
|
3530
4059
|
catch (cause) {
|
|
3531
4060
|
this._throwResponseInvalidBodyError({
|
|
@@ -3533,11 +4062,10 @@ class RelayerV2AsyncRequest {
|
|
|
3533
4062
|
status: responseStatus,
|
|
3534
4063
|
elapsed,
|
|
3535
4064
|
cause: cause,
|
|
4065
|
+
bodyJson: safeJSONstringify(bodyJson),
|
|
3536
4066
|
});
|
|
3537
4067
|
}
|
|
3538
|
-
|
|
3539
|
-
if (retry_after_sec < 1)
|
|
3540
|
-
retry_after_sec = 1;
|
|
4068
|
+
const retryAfterMs = this._getRetryAfterHeaderValueInMs(response);
|
|
3541
4069
|
// Async onProgress callback
|
|
3542
4070
|
this._postAsyncOnProgressCallback({
|
|
3543
4071
|
type: 'queued',
|
|
@@ -3547,12 +4075,12 @@ class RelayerV2AsyncRequest {
|
|
|
3547
4075
|
requestId: bodyJson.requestId,
|
|
3548
4076
|
operation: this._relayerOperation,
|
|
3549
4077
|
jobId: this.jobId,
|
|
3550
|
-
|
|
4078
|
+
retryAfterMs,
|
|
3551
4079
|
retryCount: this._retryCount,
|
|
3552
4080
|
elapsed,
|
|
3553
4081
|
});
|
|
3554
4082
|
// Wait if needed (minimum 1s)
|
|
3555
|
-
await this._setRetryAfterTimeout(
|
|
4083
|
+
await this._setRetryAfterTimeout(retryAfterMs);
|
|
3556
4084
|
continue;
|
|
3557
4085
|
}
|
|
3558
4086
|
case 400: {
|
|
@@ -3568,6 +4096,7 @@ class RelayerV2AsyncRequest {
|
|
|
3568
4096
|
status: responseStatus,
|
|
3569
4097
|
elapsed,
|
|
3570
4098
|
cause: cause,
|
|
4099
|
+
bodyJson: safeJSONstringify(bodyJson),
|
|
3571
4100
|
});
|
|
3572
4101
|
}
|
|
3573
4102
|
this._throwRelayerV2ResponseApiError({
|
|
@@ -3590,6 +4119,7 @@ class RelayerV2AsyncRequest {
|
|
|
3590
4119
|
status: responseStatus,
|
|
3591
4120
|
elapsed,
|
|
3592
4121
|
cause: cause,
|
|
4122
|
+
bodyJson: safeJSONstringify(bodyJson),
|
|
3593
4123
|
});
|
|
3594
4124
|
}
|
|
3595
4125
|
this._throwRelayerV2ResponseApiError({
|
|
@@ -3614,6 +4144,7 @@ class RelayerV2AsyncRequest {
|
|
|
3614
4144
|
status: responseStatus,
|
|
3615
4145
|
elapsed,
|
|
3616
4146
|
cause: cause,
|
|
4147
|
+
bodyJson: safeJSONstringify(bodyJson),
|
|
3617
4148
|
});
|
|
3618
4149
|
}
|
|
3619
4150
|
this._throwRelayerV2ResponseApiError({
|
|
@@ -3638,6 +4169,7 @@ class RelayerV2AsyncRequest {
|
|
|
3638
4169
|
status: responseStatus,
|
|
3639
4170
|
elapsed,
|
|
3640
4171
|
cause: cause,
|
|
4172
|
+
bodyJson: safeJSONstringify(bodyJson),
|
|
3641
4173
|
});
|
|
3642
4174
|
}
|
|
3643
4175
|
this._throwRelayerV2ResponseApiError({
|
|
@@ -3662,6 +4194,7 @@ class RelayerV2AsyncRequest {
|
|
|
3662
4194
|
status: responseStatus,
|
|
3663
4195
|
elapsed,
|
|
3664
4196
|
cause: cause,
|
|
4197
|
+
bodyJson: safeJSONstringify(bodyJson),
|
|
3665
4198
|
});
|
|
3666
4199
|
}
|
|
3667
4200
|
this._throwRelayerV2ResponseApiError({
|
|
@@ -3699,17 +4232,20 @@ class RelayerV2AsyncRequest {
|
|
|
3699
4232
|
return bodyJson;
|
|
3700
4233
|
}
|
|
3701
4234
|
//////////////////////////////////////////////////////////////////////////////
|
|
3702
|
-
|
|
4235
|
+
_getRetryAfterHeaderValueInMs(response) {
|
|
3703
4236
|
if (!response.headers.has('Retry-After')) {
|
|
3704
4237
|
if (this._throwErrorIfNoRetryAfter) {
|
|
3705
4238
|
throw new Error(`Missing 'Retry-After' header key`);
|
|
3706
4239
|
}
|
|
3707
|
-
return RelayerV2AsyncRequest.
|
|
4240
|
+
return RelayerV2AsyncRequest.DEFAULT_RETRY_AFTER_MS;
|
|
3708
4241
|
}
|
|
3709
4242
|
try {
|
|
3710
4243
|
const n = Number.parseInt(response.headers.get('Retry-After'));
|
|
3711
4244
|
if (isUint(n)) {
|
|
3712
|
-
|
|
4245
|
+
const ms = n * 1000;
|
|
4246
|
+
return ms < RelayerV2AsyncRequest.MINIMUM_RETRY_AFTER_MS
|
|
4247
|
+
? RelayerV2AsyncRequest.MINIMUM_RETRY_AFTER_MS
|
|
4248
|
+
: ms;
|
|
3713
4249
|
}
|
|
3714
4250
|
}
|
|
3715
4251
|
catch {
|
|
@@ -3718,7 +4254,7 @@ class RelayerV2AsyncRequest {
|
|
|
3718
4254
|
if (this._throwErrorIfNoRetryAfter) {
|
|
3719
4255
|
throw new Error(`Invalid 'Retry-After' header key`);
|
|
3720
4256
|
}
|
|
3721
|
-
return RelayerV2AsyncRequest.
|
|
4257
|
+
return RelayerV2AsyncRequest.DEFAULT_RETRY_AFTER_MS;
|
|
3722
4258
|
}
|
|
3723
4259
|
//////////////////////////////////////////////////////////////////////////////
|
|
3724
4260
|
// JobId
|
|
@@ -3757,17 +4293,19 @@ class RelayerV2AsyncRequest {
|
|
|
3757
4293
|
this._assert(this._jobId === undefined, 'this._jobId === undefined');
|
|
3758
4294
|
this._assert(!this._state.terminated, '!this._state.terminated');
|
|
3759
4295
|
this._assert(!this._state.fetching, '!this._state.fetching');
|
|
3760
|
-
this._trace('_fetchPost',
|
|
4296
|
+
this._trace('_fetchPost', this._url);
|
|
3761
4297
|
const init = setAuth({
|
|
3762
4298
|
method: 'POST',
|
|
3763
4299
|
headers: {
|
|
3764
4300
|
'Content-Type': 'application/json',
|
|
4301
|
+
'ZAMA-SDK-VERSION': `${version}`,
|
|
4302
|
+
'ZAMA-SDK-NAME': `${sdkName}`,
|
|
3765
4303
|
},
|
|
3766
4304
|
body: JSON.stringify(this._payload),
|
|
3767
4305
|
...(this._internalAbortSignal
|
|
3768
4306
|
? { signal: this._internalAbortSignal }
|
|
3769
4307
|
: {}),
|
|
3770
|
-
}, this.
|
|
4308
|
+
}, this._fhevmAuth);
|
|
3771
4309
|
this._state.fetching = true;
|
|
3772
4310
|
let response;
|
|
3773
4311
|
try {
|
|
@@ -3811,9 +4349,16 @@ class RelayerV2AsyncRequest {
|
|
|
3811
4349
|
this._assert(!this._state.terminated, '!this._state.terminated');
|
|
3812
4350
|
this._assert(!this._state.fetching, '!this._state.fetching');
|
|
3813
4351
|
this._trace('_fetchGet', `jobId=${this.jobId}`);
|
|
3814
|
-
const init =
|
|
3815
|
-
|
|
3816
|
-
:
|
|
4352
|
+
const init = {
|
|
4353
|
+
method: 'GET',
|
|
4354
|
+
headers: {
|
|
4355
|
+
'ZAMA-SDK-VERSION': `${version}`,
|
|
4356
|
+
'ZAMA-SDK-NAME': `${sdkName}`,
|
|
4357
|
+
},
|
|
4358
|
+
...(this._internalAbortSignal
|
|
4359
|
+
? { signal: this._internalAbortSignal }
|
|
4360
|
+
: {}),
|
|
4361
|
+
};
|
|
3817
4362
|
this._state.fetching = true;
|
|
3818
4363
|
let response;
|
|
3819
4364
|
try {
|
|
@@ -3887,7 +4432,18 @@ class RelayerV2AsyncRequest {
|
|
|
3887
4432
|
if (signal.reason !== 'cancel') {
|
|
3888
4433
|
this._assert(!this._state.canceled, '!this._state.canceled');
|
|
3889
4434
|
}
|
|
3890
|
-
this.
|
|
4435
|
+
this._postAsyncOnProgressCallback({
|
|
4436
|
+
type: 'abort',
|
|
4437
|
+
url: this._url,
|
|
4438
|
+
...(this._jobId ? { jobId: this._jobId } : {}),
|
|
4439
|
+
operation: this._relayerOperation,
|
|
4440
|
+
retryCount: this._retryCount,
|
|
4441
|
+
});
|
|
4442
|
+
this._terminate('abort', new RelayerV2AbortError({
|
|
4443
|
+
operation: this._relayerOperation,
|
|
4444
|
+
jobId: this._jobId,
|
|
4445
|
+
url: this._url,
|
|
4446
|
+
}));
|
|
3891
4447
|
};
|
|
3892
4448
|
//////////////////////////////////////////////////////////////////////////////
|
|
3893
4449
|
// Terminate
|
|
@@ -3911,7 +4467,7 @@ class RelayerV2AsyncRequest {
|
|
|
3911
4467
|
this._terminateReason = reason;
|
|
3912
4468
|
this._terminateError = error;
|
|
3913
4469
|
this._state.terminated = true;
|
|
3914
|
-
this._tryClearRetryAfterTimeout();
|
|
4470
|
+
this._tryClearRetryAfterTimeout(error);
|
|
3915
4471
|
this._tryClearGlobalRequestTimeout();
|
|
3916
4472
|
const is = this._internalAbortSignal;
|
|
3917
4473
|
const es = this._externalAbortSignal;
|
|
@@ -3933,7 +4489,7 @@ class RelayerV2AsyncRequest {
|
|
|
3933
4489
|
// Debug
|
|
3934
4490
|
this._assert(!this._state.terminated, '!this._state.terminated');
|
|
3935
4491
|
this._assert(this._retryAfterTimeoutID === undefined, 'this._retryAfterTimeoutID === undefined');
|
|
3936
|
-
this._assert(delayMs >=
|
|
4492
|
+
this._assert(delayMs >= RelayerV2AsyncRequest.MINIMUM_RETRY_AFTER_MS, `delayMs >= ${RelayerV2AsyncRequest.MINIMUM_RETRY_AFTER_MS}`);
|
|
3937
4493
|
this._trace('_setRetryAfterTimeout', `delayMs=${delayMs}`);
|
|
3938
4494
|
if (this._retryAfterTimeoutID !== undefined) {
|
|
3939
4495
|
return Promise.reject(new Error(`retry-after already running.`));
|
|
@@ -3953,7 +4509,7 @@ class RelayerV2AsyncRequest {
|
|
|
3953
4509
|
return p;
|
|
3954
4510
|
}
|
|
3955
4511
|
//////////////////////////////////////////////////////////////////////////////
|
|
3956
|
-
_tryClearRetryAfterTimeout() {
|
|
4512
|
+
_tryClearRetryAfterTimeout(error) {
|
|
3957
4513
|
if (this._retryAfterTimeoutID === undefined) {
|
|
3958
4514
|
// Debug
|
|
3959
4515
|
this._assert(this._retryAfterTimeoutPromiseFuncReject === undefined, 'this._retryAfterTimeoutPromiseFuncReject === undefined');
|
|
@@ -3964,7 +4520,8 @@ class RelayerV2AsyncRequest {
|
|
|
3964
4520
|
this._retryAfterTimeoutID = undefined;
|
|
3965
4521
|
this._retryAfterTimeoutPromiseFuncReject = undefined;
|
|
3966
4522
|
clearTimeout(tid);
|
|
3967
|
-
reject
|
|
4523
|
+
// Calling reject will
|
|
4524
|
+
reject(error ?? new Error('_tryClearRetryAfterTimeout'));
|
|
3968
4525
|
}
|
|
3969
4526
|
//////////////////////////////////////////////////////////////////////////////
|
|
3970
4527
|
// Global Request Timeout
|
|
@@ -3979,7 +4536,24 @@ class RelayerV2AsyncRequest {
|
|
|
3979
4536
|
this._requestGlobalTimeoutID = setTimeout(callback, delayMs);
|
|
3980
4537
|
}
|
|
3981
4538
|
_handleGlobalRequestTimeout() {
|
|
3982
|
-
this.
|
|
4539
|
+
this._state.timeout = true;
|
|
4540
|
+
// Debug state-check guards:
|
|
4541
|
+
this._assert(this instanceof RelayerV2AsyncRequest, `this instanceof RelayerV2AsyncRequest`);
|
|
4542
|
+
this._assert(!this._state.terminated, `!this._state.terminated`);
|
|
4543
|
+
this._assert(!this._state.timeout, '!this._state.timeout');
|
|
4544
|
+
this._postAsyncOnProgressCallback({
|
|
4545
|
+
type: 'timeout',
|
|
4546
|
+
url: this._url,
|
|
4547
|
+
...(this._jobId ? { jobId: this._jobId } : {}),
|
|
4548
|
+
operation: this._relayerOperation,
|
|
4549
|
+
retryCount: this._retryCount,
|
|
4550
|
+
});
|
|
4551
|
+
this._terminate('timeout', new RelayerV2TimeoutError({
|
|
4552
|
+
operation: this._relayerOperation,
|
|
4553
|
+
jobId: this._jobId,
|
|
4554
|
+
url: this._url,
|
|
4555
|
+
timeoutMs: this._requestMaxDurationInMs,
|
|
4556
|
+
}));
|
|
3983
4557
|
}
|
|
3984
4558
|
_tryClearGlobalRequestTimeout() {
|
|
3985
4559
|
if (this._requestGlobalTimeoutID === undefined) {
|
|
@@ -4066,20 +4640,11 @@ class RelayerV2AsyncRequest {
|
|
|
4066
4640
|
elapsed,
|
|
4067
4641
|
});
|
|
4068
4642
|
}
|
|
4069
|
-
_throwInvalidResponseError(params) {
|
|
4070
|
-
throw new RelayerV2ResponseInvalidBodyError({
|
|
4071
|
-
...params,
|
|
4072
|
-
url: this._url,
|
|
4073
|
-
operation: this._relayerOperation,
|
|
4074
|
-
state: { ...this._state },
|
|
4075
|
-
retryCount: this._retryCount,
|
|
4076
|
-
});
|
|
4077
|
-
}
|
|
4078
4643
|
_throwResponseInvalidBodyError(params) {
|
|
4079
4644
|
throw new RelayerV2ResponseInvalidBodyError({
|
|
4080
4645
|
...params,
|
|
4081
4646
|
url: this._url,
|
|
4082
|
-
jobId: this.
|
|
4647
|
+
jobId: this._jobId,
|
|
4083
4648
|
operation: this._relayerOperation,
|
|
4084
4649
|
state: { ...this._state },
|
|
4085
4650
|
retryCount: this._retryCount,
|
|
@@ -4150,7 +4715,7 @@ function assertIsRelayerV2KeyData(value, name) {
|
|
|
4150
4715
|
assertRecordStringProperty(value, 'dataId', name);
|
|
4151
4716
|
assertRecordStringArrayProperty(value, 'urls', name);
|
|
4152
4717
|
}
|
|
4153
|
-
function
|
|
4718
|
+
function toRelayerV1KeyUrlResponse(response) {
|
|
4154
4719
|
const fheKeyInfoV1 = response.response.fheKeyInfo.map((v2Info) => ({
|
|
4155
4720
|
fhe_public_key: {
|
|
4156
4721
|
data_id: v2Info.fhePublicKey.dataId,
|
|
@@ -4180,7 +4745,7 @@ class RelayerV2Provider extends AbstractRelayerProvider {
|
|
|
4180
4745
|
return 2;
|
|
4181
4746
|
}
|
|
4182
4747
|
async fetchGetKeyUrlV2() {
|
|
4183
|
-
const response = await
|
|
4748
|
+
const response = await fetchRelayerV1Get('KEY_URL', this.keyUrl);
|
|
4184
4749
|
// Relayer error
|
|
4185
4750
|
try {
|
|
4186
4751
|
assertIsRelayerV2GetResponseKeyUrl(response, 'fetchGetKeyUrl()');
|
|
@@ -4194,39 +4759,36 @@ class RelayerV2Provider extends AbstractRelayerProvider {
|
|
|
4194
4759
|
}
|
|
4195
4760
|
async fetchGetKeyUrl() {
|
|
4196
4761
|
const response = await this.fetchGetKeyUrlV2();
|
|
4197
|
-
return
|
|
4762
|
+
return toRelayerV1KeyUrlResponse(response);
|
|
4198
4763
|
}
|
|
4199
|
-
async fetchPostInputProof(payload,
|
|
4764
|
+
async fetchPostInputProof(payload, options) {
|
|
4200
4765
|
const request = new RelayerV2AsyncRequest({
|
|
4201
4766
|
relayerOperation: 'INPUT_PROOF',
|
|
4202
4767
|
url: this.inputProof,
|
|
4203
4768
|
payload,
|
|
4204
|
-
|
|
4205
|
-
...fetchOptions,
|
|
4769
|
+
options,
|
|
4206
4770
|
});
|
|
4207
4771
|
const result = (await request.run());
|
|
4208
4772
|
assertIsRelayerInputProofResult(result, 'fetchPostInputProof()');
|
|
4209
4773
|
return result;
|
|
4210
4774
|
}
|
|
4211
|
-
async fetchPostPublicDecrypt(payload,
|
|
4775
|
+
async fetchPostPublicDecrypt(payload, options) {
|
|
4212
4776
|
const request = new RelayerV2AsyncRequest({
|
|
4213
4777
|
relayerOperation: 'PUBLIC_DECRYPT',
|
|
4214
4778
|
url: this.publicDecrypt,
|
|
4215
4779
|
payload,
|
|
4216
|
-
|
|
4217
|
-
...fetchOptions,
|
|
4780
|
+
options,
|
|
4218
4781
|
});
|
|
4219
4782
|
const result = await request.run();
|
|
4220
4783
|
assertIsRelayerPublicDecryptResult(result, 'fetchPostPublicDecrypt()');
|
|
4221
4784
|
return result;
|
|
4222
4785
|
}
|
|
4223
|
-
async fetchPostUserDecrypt(payload,
|
|
4786
|
+
async fetchPostUserDecrypt(payload, options) {
|
|
4224
4787
|
const request = new RelayerV2AsyncRequest({
|
|
4225
4788
|
relayerOperation: 'USER_DECRYPT',
|
|
4226
4789
|
url: this.userDecrypt,
|
|
4227
4790
|
payload,
|
|
4228
|
-
|
|
4229
|
-
...fetchOptions,
|
|
4791
|
+
options,
|
|
4230
4792
|
});
|
|
4231
4793
|
const result = (await request.run());
|
|
4232
4794
|
assertIsRelayerUserDecryptResult(result.result, 'fetchPostUserDecrypt()');
|
|
@@ -4234,6 +4796,16 @@ class RelayerV2Provider extends AbstractRelayerProvider {
|
|
|
4234
4796
|
}
|
|
4235
4797
|
}
|
|
4236
4798
|
|
|
4799
|
+
class TFHECrsError extends RelayerErrorBase {
|
|
4800
|
+
constructor({ message, cause }) {
|
|
4801
|
+
super({
|
|
4802
|
+
message,
|
|
4803
|
+
name: 'TFHECrsError',
|
|
4804
|
+
...(cause ? { cause: ensureError(cause) } : {}),
|
|
4805
|
+
});
|
|
4806
|
+
}
|
|
4807
|
+
}
|
|
4808
|
+
|
|
4237
4809
|
class AbstractRelayerFhevm {
|
|
4238
4810
|
}
|
|
4239
4811
|
|
|
@@ -4248,6 +4820,15 @@ class TFHECrs {
|
|
|
4248
4820
|
this._bits = params.bits;
|
|
4249
4821
|
this._srcUrl = params.srcUrl;
|
|
4250
4822
|
}
|
|
4823
|
+
get id() {
|
|
4824
|
+
return this._id;
|
|
4825
|
+
}
|
|
4826
|
+
get bits() {
|
|
4827
|
+
return this._bits;
|
|
4828
|
+
}
|
|
4829
|
+
get srcUrl() {
|
|
4830
|
+
return this._srcUrl;
|
|
4831
|
+
}
|
|
4251
4832
|
/*
|
|
4252
4833
|
{
|
|
4253
4834
|
id: string,
|
|
@@ -4350,20 +4931,58 @@ class TFHECrs {
|
|
|
4350
4931
|
return TFHECrs._fromUrl(params);
|
|
4351
4932
|
}
|
|
4352
4933
|
else {
|
|
4353
|
-
throw new
|
|
4934
|
+
throw new TFHECrsError({
|
|
4935
|
+
message: 'Invalid public key (deserialization failed)',
|
|
4936
|
+
});
|
|
4354
4937
|
}
|
|
4355
4938
|
}
|
|
4939
|
+
/*
|
|
4940
|
+
{
|
|
4941
|
+
id: string;
|
|
4942
|
+
data: Uint8Array;
|
|
4943
|
+
bits: number;
|
|
4944
|
+
srcUrl?: string;
|
|
4945
|
+
}
|
|
4946
|
+
*/
|
|
4356
4947
|
static fromBytes(params) {
|
|
4357
4948
|
try {
|
|
4358
4949
|
TFHECrs.assertKeyBytesType(params, 'arg');
|
|
4359
4950
|
return TFHECrs._fromBytes(params);
|
|
4360
4951
|
}
|
|
4361
4952
|
catch (e) {
|
|
4362
|
-
throw new
|
|
4953
|
+
throw new TFHECrsError({
|
|
4954
|
+
message: 'Invalid public key (deserialization failed)',
|
|
4363
4955
|
cause: e,
|
|
4364
4956
|
});
|
|
4365
4957
|
}
|
|
4366
4958
|
}
|
|
4959
|
+
/*
|
|
4960
|
+
{
|
|
4961
|
+
id: string;
|
|
4962
|
+
data: BytesHex;
|
|
4963
|
+
bits: number;
|
|
4964
|
+
srcUrl?: string;
|
|
4965
|
+
}
|
|
4966
|
+
*/
|
|
4967
|
+
static fromBytesHex(params) {
|
|
4968
|
+
let data;
|
|
4969
|
+
try {
|
|
4970
|
+
assertRecordStringProperty(params, 'data', 'arg');
|
|
4971
|
+
data = hexToBytesFaster(params.data, true /* strict */);
|
|
4972
|
+
}
|
|
4973
|
+
catch (e) {
|
|
4974
|
+
throw new TFHECrsError({
|
|
4975
|
+
message: 'Invalid public key (deserialization failed)',
|
|
4976
|
+
cause: e,
|
|
4977
|
+
});
|
|
4978
|
+
}
|
|
4979
|
+
return TFHECrs.fromBytes({
|
|
4980
|
+
id: params?.id,
|
|
4981
|
+
bits: params?.bits,
|
|
4982
|
+
srcUrl: params?.srcUrl,
|
|
4983
|
+
data,
|
|
4984
|
+
});
|
|
4985
|
+
}
|
|
4367
4986
|
static _fromBytes(params) {
|
|
4368
4987
|
const _params = {
|
|
4369
4988
|
compactPkeCrs: TFHE.CompactPkeCrs.safe_deserialize(params.data, SERIALIZED_SIZE_LIMIT_CRS),
|
|
@@ -4379,7 +4998,50 @@ class TFHECrs {
|
|
|
4379
4998
|
return TFHECrs._fromPublicParamsBytes(params);
|
|
4380
4999
|
}
|
|
4381
5000
|
catch (e) {
|
|
4382
|
-
throw new
|
|
5001
|
+
throw new TFHECrsError({
|
|
5002
|
+
message: 'Invalid public key (deserialization failed)',
|
|
5003
|
+
cause: e,
|
|
5004
|
+
});
|
|
5005
|
+
}
|
|
5006
|
+
}
|
|
5007
|
+
static fromBitsPublicParamsBytes(bits, params) {
|
|
5008
|
+
if (bits === undefined) {
|
|
5009
|
+
throw new TFHECrsError({ message: 'Missing PublicParams bits format' });
|
|
5010
|
+
}
|
|
5011
|
+
if (bits !== 2048) {
|
|
5012
|
+
throw new TFHECrsError({
|
|
5013
|
+
message: `Unsupported PublicParams bits format '${bits}'`,
|
|
5014
|
+
});
|
|
5015
|
+
}
|
|
5016
|
+
try {
|
|
5017
|
+
assertRecordStringProperty(params, 'publicParamsId', `arg`);
|
|
5018
|
+
assertUint8ArrayProperty(params, 'publicParams', `arg`);
|
|
5019
|
+
return TFHECrs._fromPublicParamsBytes({
|
|
5020
|
+
2048: params,
|
|
5021
|
+
});
|
|
5022
|
+
}
|
|
5023
|
+
catch (e) {
|
|
5024
|
+
throw new TFHECrsError({
|
|
5025
|
+
message: 'Invalid public key (deserialization failed)',
|
|
5026
|
+
cause: e,
|
|
5027
|
+
});
|
|
5028
|
+
}
|
|
5029
|
+
}
|
|
5030
|
+
static fromPublicParamsBytesHex(params) {
|
|
5031
|
+
try {
|
|
5032
|
+
assertNonNullableRecordProperty(params, '2048', 'arg');
|
|
5033
|
+
assertRecordStringProperty(params['2048'], 'publicParamsId', `arg.2048`);
|
|
5034
|
+
assertRecordStringProperty(params['2048'], 'publicParams', `arg.2048`);
|
|
5035
|
+
return TFHECrs._fromPublicParamsBytes({
|
|
5036
|
+
2048: {
|
|
5037
|
+
publicParams: hexToBytesFaster(params['2048'].publicParams, true /* strict */),
|
|
5038
|
+
publicParamsId: params['2048'].publicParamsId,
|
|
5039
|
+
},
|
|
5040
|
+
});
|
|
5041
|
+
}
|
|
5042
|
+
catch (e) {
|
|
5043
|
+
throw new TFHECrsError({
|
|
5044
|
+
message: 'Invalid public key (deserialization failed)',
|
|
4383
5045
|
cause: e,
|
|
4384
5046
|
});
|
|
4385
5047
|
}
|
|
@@ -4397,7 +5059,8 @@ class TFHECrs {
|
|
|
4397
5059
|
return TFHECrs._fromUrl(params);
|
|
4398
5060
|
}
|
|
4399
5061
|
catch (e) {
|
|
4400
|
-
throw new
|
|
5062
|
+
throw new TFHECrsError({
|
|
5063
|
+
message: 'Impossible to fetch public key: wrong relayer url.',
|
|
4401
5064
|
cause: e,
|
|
4402
5065
|
});
|
|
4403
5066
|
}
|
|
@@ -4428,6 +5091,22 @@ class TFHECrs {
|
|
|
4428
5091
|
...(this._srcUrl ? { srcUrl: this._srcUrl } : {}),
|
|
4429
5092
|
};
|
|
4430
5093
|
}
|
|
5094
|
+
/*
|
|
5095
|
+
{
|
|
5096
|
+
id: string,
|
|
5097
|
+
bits: number,
|
|
5098
|
+
data: BytesHex,
|
|
5099
|
+
srcUrl?: string
|
|
5100
|
+
}
|
|
5101
|
+
*/
|
|
5102
|
+
toBytesHex() {
|
|
5103
|
+
return {
|
|
5104
|
+
data: bytesToHexLarge(this._compactPkeCrs.safe_serialize(SERIALIZED_SIZE_LIMIT_CRS)),
|
|
5105
|
+
id: this._id,
|
|
5106
|
+
bits: this._bits,
|
|
5107
|
+
...(this._srcUrl ? { srcUrl: this._srcUrl } : {}),
|
|
5108
|
+
};
|
|
5109
|
+
}
|
|
4431
5110
|
/*
|
|
4432
5111
|
{
|
|
4433
5112
|
2048: {
|
|
@@ -4436,9 +5115,11 @@ class TFHECrs {
|
|
|
4436
5115
|
}
|
|
4437
5116
|
}
|
|
4438
5117
|
*/
|
|
4439
|
-
|
|
5118
|
+
toPublicParams2048Wasm() {
|
|
4440
5119
|
if (this._bits !== 2048) {
|
|
4441
|
-
throw new
|
|
5120
|
+
throw new TFHECrsError({
|
|
5121
|
+
message: `Unsupported PublicParams bits format '2048'`,
|
|
5122
|
+
});
|
|
4442
5123
|
}
|
|
4443
5124
|
const pp = {
|
|
4444
5125
|
2048: {
|
|
@@ -4456,9 +5137,11 @@ class TFHECrs {
|
|
|
4456
5137
|
}
|
|
4457
5138
|
}
|
|
4458
5139
|
*/
|
|
4459
|
-
|
|
5140
|
+
toPublicParams2048Bytes() {
|
|
4460
5141
|
if (this._bits !== 2048) {
|
|
4461
|
-
throw new
|
|
5142
|
+
throw new TFHECrsError({
|
|
5143
|
+
message: `Unsupported PublicParams bits format '2048'`,
|
|
5144
|
+
});
|
|
4462
5145
|
}
|
|
4463
5146
|
const pp = {
|
|
4464
5147
|
2048: {
|
|
@@ -4468,6 +5151,64 @@ class TFHECrs {
|
|
|
4468
5151
|
};
|
|
4469
5152
|
return pp;
|
|
4470
5153
|
}
|
|
5154
|
+
/*
|
|
5155
|
+
{
|
|
5156
|
+
2048: {
|
|
5157
|
+
publicParamsId: string,
|
|
5158
|
+
publicParams: BytesHex
|
|
5159
|
+
}
|
|
5160
|
+
}
|
|
5161
|
+
*/
|
|
5162
|
+
toPublicParams2048BytesHex() {
|
|
5163
|
+
if (this._bits === undefined) {
|
|
5164
|
+
throw new TFHECrsError({ message: 'Missing PublicParams bits format' });
|
|
5165
|
+
}
|
|
5166
|
+
if (this._bits !== 2048) {
|
|
5167
|
+
throw new TFHECrsError({
|
|
5168
|
+
message: `Unsupported PublicParams bits format '${this._bits}'`,
|
|
5169
|
+
});
|
|
5170
|
+
}
|
|
5171
|
+
const pp = {
|
|
5172
|
+
2048: {
|
|
5173
|
+
publicParams: this.toBytesHex().data,
|
|
5174
|
+
publicParamsId: this._id,
|
|
5175
|
+
},
|
|
5176
|
+
};
|
|
5177
|
+
return pp;
|
|
5178
|
+
}
|
|
5179
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
5180
|
+
// JSON
|
|
5181
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
5182
|
+
/*
|
|
5183
|
+
{
|
|
5184
|
+
__type: 'TFHECrs',
|
|
5185
|
+
id: string,
|
|
5186
|
+
data: BytesHex,
|
|
5187
|
+
srcUrl?: string
|
|
5188
|
+
}
|
|
5189
|
+
*/
|
|
5190
|
+
toJSON() {
|
|
5191
|
+
return {
|
|
5192
|
+
__type: 'TFHECrs',
|
|
5193
|
+
...this.toBytesHex(),
|
|
5194
|
+
};
|
|
5195
|
+
}
|
|
5196
|
+
static fromJSON(json) {
|
|
5197
|
+
if (json.__type !== 'TFHECrs') {
|
|
5198
|
+
throw new TFHECrsError({ message: 'Invalid TFHECrs JSON.' });
|
|
5199
|
+
}
|
|
5200
|
+
return TFHECrs.fromBytesHex(json);
|
|
5201
|
+
}
|
|
5202
|
+
}
|
|
5203
|
+
|
|
5204
|
+
class TFHEPublicKeyError extends RelayerErrorBase {
|
|
5205
|
+
constructor({ message, cause }) {
|
|
5206
|
+
super({
|
|
5207
|
+
message,
|
|
5208
|
+
name: 'TFHEPublicKeyError',
|
|
5209
|
+
...(cause ? { cause: ensureError(cause) } : {}),
|
|
5210
|
+
});
|
|
5211
|
+
}
|
|
4471
5212
|
}
|
|
4472
5213
|
|
|
4473
5214
|
class TFHEPublicKey {
|
|
@@ -4479,6 +5220,12 @@ class TFHEPublicKey {
|
|
|
4479
5220
|
this._tfheCompactPublicKey = params.tfheCompactPublicKey;
|
|
4480
5221
|
this._srcUrl = params.srcUrl;
|
|
4481
5222
|
}
|
|
5223
|
+
get id() {
|
|
5224
|
+
return this._id;
|
|
5225
|
+
}
|
|
5226
|
+
get srcUrl() {
|
|
5227
|
+
return this._srcUrl;
|
|
5228
|
+
}
|
|
4482
5229
|
/*
|
|
4483
5230
|
{
|
|
4484
5231
|
id: string,
|
|
@@ -4563,6 +5310,30 @@ class TFHEPublicKey {
|
|
|
4563
5310
|
});
|
|
4564
5311
|
}
|
|
4565
5312
|
}
|
|
5313
|
+
/*
|
|
5314
|
+
{
|
|
5315
|
+
id: string,
|
|
5316
|
+
data: BytesHex,
|
|
5317
|
+
srcUrl?: string
|
|
5318
|
+
}
|
|
5319
|
+
*/
|
|
5320
|
+
static fromBytesHex(params) {
|
|
5321
|
+
let data;
|
|
5322
|
+
try {
|
|
5323
|
+
assertRecordStringProperty(params, 'data', 'arg');
|
|
5324
|
+
data = hexToBytesFaster(params.data, true /* strict */);
|
|
5325
|
+
}
|
|
5326
|
+
catch (e) {
|
|
5327
|
+
throw new Error('Invalid public key (deserialization failed)', {
|
|
5328
|
+
cause: e,
|
|
5329
|
+
});
|
|
5330
|
+
}
|
|
5331
|
+
return TFHEPublicKey.fromBytes({
|
|
5332
|
+
id: params?.id,
|
|
5333
|
+
srcUrl: params?.srcUrl,
|
|
5334
|
+
data,
|
|
5335
|
+
});
|
|
5336
|
+
}
|
|
4566
5337
|
/*
|
|
4567
5338
|
{
|
|
4568
5339
|
id: string,
|
|
@@ -4623,6 +5394,20 @@ class TFHEPublicKey {
|
|
|
4623
5394
|
...(this._srcUrl ? { srcUrl: this._srcUrl } : {}),
|
|
4624
5395
|
};
|
|
4625
5396
|
}
|
|
5397
|
+
/*
|
|
5398
|
+
{
|
|
5399
|
+
id: string,
|
|
5400
|
+
data: BytesHex,
|
|
5401
|
+
srcUrl?: string
|
|
5402
|
+
}
|
|
5403
|
+
*/
|
|
5404
|
+
toBytesHex() {
|
|
5405
|
+
return {
|
|
5406
|
+
data: bytesToHexLarge(this._tfheCompactPublicKey.safe_serialize(SERIALIZED_SIZE_LIMIT_PK)),
|
|
5407
|
+
id: this._id,
|
|
5408
|
+
...(this._srcUrl ? { srcUrl: this._srcUrl } : {}),
|
|
5409
|
+
};
|
|
5410
|
+
}
|
|
4626
5411
|
/*
|
|
4627
5412
|
{
|
|
4628
5413
|
publicKey: TFHE.TfheCompactPublicKey
|
|
@@ -4647,6 +5432,75 @@ class TFHEPublicKey {
|
|
|
4647
5432
|
publicKeyId: this._id,
|
|
4648
5433
|
};
|
|
4649
5434
|
}
|
|
5435
|
+
/*
|
|
5436
|
+
{
|
|
5437
|
+
publicKey: Uint8Array
|
|
5438
|
+
publicKeyId: string
|
|
5439
|
+
}
|
|
5440
|
+
*/
|
|
5441
|
+
toPublicKeyBytesHex() {
|
|
5442
|
+
return {
|
|
5443
|
+
publicKey: this.toBytesHex().data,
|
|
5444
|
+
publicKeyId: this._id,
|
|
5445
|
+
};
|
|
5446
|
+
}
|
|
5447
|
+
static _fromPublicKeyBytes(params) {
|
|
5448
|
+
return TFHEPublicKey._fromBytes({
|
|
5449
|
+
data: params.publicKey,
|
|
5450
|
+
id: params.publicKeyId,
|
|
5451
|
+
srcUrl: params.srcUrl,
|
|
5452
|
+
});
|
|
5453
|
+
}
|
|
5454
|
+
static fromPublicKeyBytesHex(params) {
|
|
5455
|
+
try {
|
|
5456
|
+
assertRecordStringProperty(params, 'publicKey', `arg`);
|
|
5457
|
+
assertRecordStringProperty(params, 'publicKeyId', `arg`);
|
|
5458
|
+
return TFHEPublicKey._fromPublicKeyBytes({
|
|
5459
|
+
publicKey: hexToBytesFaster(params.publicKey, true /* strict */),
|
|
5460
|
+
publicKeyId: params.publicKeyId,
|
|
5461
|
+
});
|
|
5462
|
+
}
|
|
5463
|
+
catch (e) {
|
|
5464
|
+
throw new Error('Invalid public key (deserialization failed)', {
|
|
5465
|
+
cause: e,
|
|
5466
|
+
});
|
|
5467
|
+
}
|
|
5468
|
+
}
|
|
5469
|
+
static fromPublicKeyBytes(params) {
|
|
5470
|
+
try {
|
|
5471
|
+
assertUint8ArrayProperty(params, 'publicKey', `arg`);
|
|
5472
|
+
assertRecordStringProperty(params, 'publicKeyId', `arg`);
|
|
5473
|
+
return TFHEPublicKey._fromPublicKeyBytes(params);
|
|
5474
|
+
}
|
|
5475
|
+
catch (e) {
|
|
5476
|
+
throw new Error('Invalid public key (deserialization failed)', {
|
|
5477
|
+
cause: e,
|
|
5478
|
+
});
|
|
5479
|
+
}
|
|
5480
|
+
}
|
|
5481
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
5482
|
+
// JSON
|
|
5483
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
5484
|
+
/*
|
|
5485
|
+
{
|
|
5486
|
+
__type: 'TFHEPublicKey',
|
|
5487
|
+
id: string,
|
|
5488
|
+
data: BytesHex,
|
|
5489
|
+
srcUrl?: string
|
|
5490
|
+
}
|
|
5491
|
+
*/
|
|
5492
|
+
toJSON() {
|
|
5493
|
+
return {
|
|
5494
|
+
__type: 'TFHEPublicKey',
|
|
5495
|
+
...this.toBytesHex(),
|
|
5496
|
+
};
|
|
5497
|
+
}
|
|
5498
|
+
static fromJSON(json) {
|
|
5499
|
+
if (json.__type !== 'TFHEPublicKey') {
|
|
5500
|
+
throw new TFHEPublicKeyError({ message: 'Invalid TFHEPublicKey JSON.' });
|
|
5501
|
+
}
|
|
5502
|
+
return TFHEPublicKey.fromBytesHex(json);
|
|
5503
|
+
}
|
|
4650
5504
|
}
|
|
4651
5505
|
|
|
4652
5506
|
//const __KEY_URL_CACHE__: Record<string, RelayerV2PublicKey> = {};
|
|
@@ -4722,7 +5576,7 @@ class RelayerV2PublicKey {
|
|
|
4722
5576
|
toBytes() {
|
|
4723
5577
|
return {
|
|
4724
5578
|
publicKey: this._publicKey.toBytes(),
|
|
4725
|
-
publicParams: this._crs2048.
|
|
5579
|
+
publicParams: this._crs2048.toPublicParams2048Bytes(),
|
|
4726
5580
|
};
|
|
4727
5581
|
}
|
|
4728
5582
|
}
|
|
@@ -4756,23 +5610,46 @@ class RelayerV2Fhevm extends AbstractRelayerFhevm {
|
|
|
4756
5610
|
get relayerProvider() {
|
|
4757
5611
|
return this._relayerProvider;
|
|
4758
5612
|
}
|
|
5613
|
+
getPublicKeyInfo() {
|
|
5614
|
+
return {
|
|
5615
|
+
id: this._relayerPublicKey.getTFHEPublicKey().id,
|
|
5616
|
+
srcUrl: this._relayerPublicKey.getTFHEPublicKey().srcUrl,
|
|
5617
|
+
};
|
|
5618
|
+
}
|
|
4759
5619
|
getPublicKeyBytes() {
|
|
4760
5620
|
return this._relayerPublicKey.getTFHEPublicKey().toPublicKeyBytes();
|
|
4761
5621
|
}
|
|
4762
5622
|
getPublicKeyWasm() {
|
|
4763
5623
|
return this._relayerPublicKey.getTFHEPublicKey().toPublicKeyWasm();
|
|
4764
5624
|
}
|
|
4765
|
-
|
|
5625
|
+
getPublicParamsBytesForBits(bits) {
|
|
5626
|
+
if (bits === undefined) {
|
|
5627
|
+
throw new TFHECrsError({ message: `Missing PublicParams bits format` });
|
|
5628
|
+
}
|
|
4766
5629
|
if (bits !== 2048) {
|
|
4767
|
-
throw new
|
|
5630
|
+
throw new TFHECrsError({
|
|
5631
|
+
message: `Unsupported PublicParams bits format '${bits}'`,
|
|
5632
|
+
});
|
|
4768
5633
|
}
|
|
4769
|
-
return this._relayerPublicKey.getTFHECrs().
|
|
5634
|
+
return this._relayerPublicKey.getTFHECrs().toPublicParams2048Bytes()['2048'];
|
|
4770
5635
|
}
|
|
4771
|
-
|
|
5636
|
+
getPublicParamsWasmForBits(bits) {
|
|
5637
|
+
if (bits === undefined) {
|
|
5638
|
+
throw new TFHECrsError({ message: `Missing PublicParams bits format` });
|
|
5639
|
+
}
|
|
4772
5640
|
if (bits !== 2048) {
|
|
4773
|
-
throw new
|
|
5641
|
+
throw new TFHECrsError({
|
|
5642
|
+
message: `Unsupported PublicParams bits format '${bits}'`,
|
|
5643
|
+
});
|
|
4774
5644
|
}
|
|
4775
|
-
return this._relayerPublicKey.getTFHECrs().
|
|
5645
|
+
return this._relayerPublicKey.getTFHECrs().toPublicParams2048Wasm()['2048'];
|
|
5646
|
+
}
|
|
5647
|
+
getPublicParamsInfo() {
|
|
5648
|
+
return {
|
|
5649
|
+
id: this._relayerPublicKey.getTFHECrs().id,
|
|
5650
|
+
bits: this._relayerPublicKey.getTFHECrs().bits,
|
|
5651
|
+
srcUrl: this._relayerPublicKey.getTFHECrs().srcUrl,
|
|
5652
|
+
};
|
|
4776
5653
|
}
|
|
4777
5654
|
}
|
|
4778
5655
|
|
|
@@ -4811,24 +5688,42 @@ class RelayerV1Fhevm extends AbstractRelayerFhevm {
|
|
|
4811
5688
|
publicKeyId: this._publicKeyData.publicKeyId,
|
|
4812
5689
|
};
|
|
4813
5690
|
}
|
|
5691
|
+
getPublicKeyInfo() {
|
|
5692
|
+
return {
|
|
5693
|
+
id: this._publicKeyData.publicKeyId,
|
|
5694
|
+
};
|
|
5695
|
+
}
|
|
5696
|
+
getPublicParamsInfo() {
|
|
5697
|
+
return {
|
|
5698
|
+
id: this._publicParamsData['2048'].publicParamsId,
|
|
5699
|
+
bits: 2048,
|
|
5700
|
+
};
|
|
5701
|
+
}
|
|
4814
5702
|
getPublicKeyWasm() {
|
|
4815
5703
|
return {
|
|
4816
5704
|
publicKey: this._publicKeyData.publicKey,
|
|
4817
5705
|
publicKeyId: this._publicKeyData.publicKeyId,
|
|
4818
5706
|
};
|
|
4819
5707
|
}
|
|
4820
|
-
|
|
5708
|
+
getPublicParamsBytesForBits(bits) {
|
|
5709
|
+
if (bits === undefined) {
|
|
5710
|
+
throw new Error(`Missing PublicParams bits format`);
|
|
5711
|
+
}
|
|
4821
5712
|
if (bits !== 2048) {
|
|
4822
|
-
throw new Error(`Unsupported PublicParams bits format ${bits}`);
|
|
5713
|
+
throw new Error(`Unsupported PublicParams bits format '${bits}'`);
|
|
4823
5714
|
}
|
|
4824
|
-
|
|
5715
|
+
const res = {
|
|
4825
5716
|
publicParams: this._publicParamsData['2048'].publicParams.safe_serialize(SERIALIZED_SIZE_LIMIT_CRS),
|
|
4826
5717
|
publicParamsId: this._publicParamsData['2048'].publicParamsId,
|
|
4827
5718
|
};
|
|
5719
|
+
return res;
|
|
4828
5720
|
}
|
|
4829
|
-
|
|
5721
|
+
getPublicParamsWasmForBits(bits) {
|
|
5722
|
+
if (bits === undefined) {
|
|
5723
|
+
throw new Error(`Missing PublicParams bits format`);
|
|
5724
|
+
}
|
|
4830
5725
|
if (bits !== 2048) {
|
|
4831
|
-
throw new Error(`Unsupported PublicParams bits format ${bits}`);
|
|
5726
|
+
throw new Error(`Unsupported PublicParams bits format '${bits}'`);
|
|
4832
5727
|
}
|
|
4833
5728
|
return {
|
|
4834
5729
|
publicParams: this._publicParamsData['2048'].publicParams,
|
|
@@ -4849,11 +5744,16 @@ async function createRelayerFhevm(config) {
|
|
|
4849
5744
|
publicParams: config.publicParams,
|
|
4850
5745
|
});
|
|
4851
5746
|
}
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
5747
|
+
else if (resolved.version === 1) {
|
|
5748
|
+
return RelayerV1Fhevm.fromConfig({
|
|
5749
|
+
relayerVersionUrl: resolved.url,
|
|
5750
|
+
publicKey: config.publicKey,
|
|
5751
|
+
publicParams: config.publicParams,
|
|
5752
|
+
});
|
|
5753
|
+
}
|
|
5754
|
+
else {
|
|
5755
|
+
throw new Error(`Invalid relayerUrl: ${config.relayerUrl}`);
|
|
5756
|
+
}
|
|
4857
5757
|
}
|
|
4858
5758
|
function _resolveRelayerUrl(value, defaultVersion) {
|
|
4859
5759
|
if (!value || typeof value !== 'string') {
|
|
@@ -4884,60 +5784,39 @@ function _resolveRelayerUrl(value, defaultVersion) {
|
|
|
4884
5784
|
};
|
|
4885
5785
|
}
|
|
4886
5786
|
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
|
|
4896
|
-
|
|
4897
|
-
|
|
4898
|
-
|
|
4899
|
-
|
|
4900
|
-
* | 8 | 2 | `euint8` | |
|
|
4901
|
-
* | 16 | 3 | `euint16` | |
|
|
4902
|
-
* | 32 | 4 | `euint32` | |
|
|
4903
|
-
* | 64 | 5 | `euint64` | |
|
|
4904
|
-
* | 128 | 6 | `euint128` | |
|
|
4905
|
-
* | 160 | 7 | `eaddress` | Used for encrypted Ethereum addresses. |
|
|
4906
|
-
* | 256 | 8 | `euint256` | The maximum supported integer size. |
|
|
4907
|
-
*/
|
|
4908
|
-
const ENCRYPTION_TYPES = {
|
|
4909
|
-
2: 0, // ebool (FheTypeId=0) is using 2 encrypted bits
|
|
4910
|
-
// euint4 (FheTypeId=1) is deprecated
|
|
4911
|
-
8: 2, // euint8 (FheTypeId=2) is using 8 encrypted bits
|
|
4912
|
-
16: 3, // euint16 (FheTypeId=3) is using 16 encrypted bits
|
|
4913
|
-
32: 4, // euint32 (FheTypeId=4) is using 32 encrypted bits
|
|
4914
|
-
64: 5, // euint64 (FheTypeId=5) is using 64 encrypted bits
|
|
4915
|
-
128: 6, // euint128 (FheTypeId=128) is using 128 encrypted bits
|
|
4916
|
-
160: 7, // eaddress (FheTypeId=7) is using 160 encrypted bits
|
|
4917
|
-
256: 8, // euint256 (FheTypeId=8) is using 256 encrypted bits
|
|
5787
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
5788
|
+
// MainnetConfig
|
|
5789
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
5790
|
+
const MainnetConfig = {
|
|
5791
|
+
aclContractAddress: '0xcA2E8f1F656CD25C01F05d0b243Ab1ecd4a8ffb6',
|
|
5792
|
+
kmsContractAddress: '0x77627828a55156b04Ac0DC0eb30467f1a552BB03',
|
|
5793
|
+
inputVerifierContractAddress: '0xCe0FC2e05CFff1B719EFF7169f7D80Af770c8EA2',
|
|
5794
|
+
verifyingContractAddressDecryption: '0x0f6024a97684f7d90ddb0fAAD79cB15F2C888D24',
|
|
5795
|
+
verifyingContractAddressInputVerification: '0xcB1bB072f38bdAF0F328CdEf1Fc6eDa1DF029287',
|
|
5796
|
+
chainId: 1,
|
|
5797
|
+
gatewayChainId: 261131,
|
|
5798
|
+
network: 'https://ethereum-rpc.publicnode.com',
|
|
5799
|
+
relayerUrl: 'https://relayer.mainnet.zama.org',
|
|
4918
5800
|
};
|
|
4919
|
-
|
|
5801
|
+
Object.freeze(MainnetConfig);
|
|
5802
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
5803
|
+
// SepoliaConfig
|
|
5804
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
4920
5805
|
const SepoliaConfig = {
|
|
4921
|
-
// ACL_CONTRACT_ADDRESS (FHEVM Host chain)
|
|
4922
5806
|
aclContractAddress: '0xf0Ffdc93b7E186bC2f8CB3dAA75D86d1930A433D',
|
|
4923
|
-
// KMS_VERIFIER_CONTRACT_ADDRESS (FHEVM Host chain)
|
|
4924
5807
|
kmsContractAddress: '0xbE0E383937d564D7FF0BC3b46c51f0bF8d5C311A',
|
|
4925
|
-
// INPUT_VERIFIER_CONTRACT_ADDRESS (FHEVM Host chain)
|
|
4926
5808
|
inputVerifierContractAddress: '0xBBC1fFCdc7C316aAAd72E807D9b0272BE8F84DA0',
|
|
4927
|
-
// DECRYPTION_ADDRESS (Gateway chain)
|
|
4928
5809
|
verifyingContractAddressDecryption: '0x5D8BD78e2ea6bbE41f26dFe9fdaEAa349e077478',
|
|
4929
|
-
// INPUT_VERIFICATION_ADDRESS (Gateway chain)
|
|
4930
5810
|
verifyingContractAddressInputVerification: '0x483b9dE06E4E4C7D35CCf5837A1668487406D955',
|
|
4931
|
-
// FHEVM Host chain id
|
|
4932
5811
|
chainId: 11155111,
|
|
4933
|
-
// Gateway chain id
|
|
4934
5812
|
gatewayChainId: 10901,
|
|
4935
|
-
// Optional RPC provider to host chain
|
|
4936
5813
|
network: 'https://ethereum-sepolia-rpc.publicnode.com',
|
|
4937
|
-
// Relayer URL
|
|
4938
5814
|
relayerUrl: 'https://relayer.testnet.zama.org',
|
|
4939
5815
|
};
|
|
4940
5816
|
Object.freeze(SepoliaConfig);
|
|
5817
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
5818
|
+
// createInstance
|
|
5819
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
4941
5820
|
const createInstance = async (config) => {
|
|
4942
5821
|
const { verifyingContractAddressDecryption, verifyingContractAddressInputVerification, publicKey, inputVerifierContractAddress, kmsContractAddress, aclContractAddress, gatewayChainId, auth, } = config;
|
|
4943
5822
|
if (!isChecksummedAddress(aclContractAddress)) {
|
|
@@ -4969,29 +5848,33 @@ const createInstance = async (config) => {
|
|
|
4969
5848
|
defaultRelayerVersion: 1,
|
|
4970
5849
|
});
|
|
4971
5850
|
const chainId = await getChainId(provider, config);
|
|
4972
|
-
// const relayerVersionUrl = `${config.relayerUrl!}/v1`;
|
|
4973
|
-
// const publicKeyData = await getTfheCompactPublicKey({
|
|
4974
|
-
// relayerVersionUrl: relayerFhevm.relayerVersionUrl,
|
|
4975
|
-
// publicKey: config.publicKey,
|
|
4976
|
-
// });
|
|
4977
|
-
//const aaa = relayerFhevm.getPublicKey();
|
|
4978
|
-
// const publicParamsData = await getPublicParams({
|
|
4979
|
-
// relayerVersionUrl,
|
|
4980
|
-
// publicParams: config.publicParams,
|
|
4981
|
-
// });
|
|
4982
5851
|
const kmsSigners = await getKMSSigners(provider, kmsContractAddress);
|
|
4983
5852
|
const thresholdKMSSigners = await getKMSSignersThreshold(provider, kmsContractAddress);
|
|
4984
5853
|
const coprocessorSigners = await getCoprocessorSigners(provider, inputVerifierContractAddress);
|
|
4985
5854
|
const thresholdCoprocessorSigners = await getCoprocessorSignersThreshold(provider, inputVerifierContractAddress);
|
|
4986
5855
|
return {
|
|
4987
|
-
createEncryptedInput: createRelayerEncryptedInput(aclContractAddress, verifyingContractAddressInputVerification, chainId, gatewayChainId,
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
5856
|
+
createEncryptedInput: createRelayerEncryptedInput(aclContractAddress, verifyingContractAddressInputVerification, chainId, gatewayChainId, relayerFhevm.relayerProvider, relayerFhevm.getPublicKeyWasm().publicKey, { 2048: relayerFhevm.getPublicParamsWasmForBits(2048) }, coprocessorSigners, thresholdCoprocessorSigners, auth && { auth }),
|
|
5857
|
+
requestZKProofVerification: (zkProof, options) => {
|
|
5858
|
+
if (zkProof.chainId !== chainId ||
|
|
5859
|
+
zkProof.aclContractAddress !== aclContractAddress) {
|
|
5860
|
+
throw new Error('Invalid ZKProof');
|
|
5861
|
+
}
|
|
5862
|
+
return requestCiphertextWithZKProofVerification({
|
|
5863
|
+
ciphertext: zkProof.ciphertextWithZkProof,
|
|
5864
|
+
aclContractAddress: aclContractAddress,
|
|
5865
|
+
contractAddress: zkProof.contractAddress,
|
|
5866
|
+
userAddress: zkProof.userAddress,
|
|
5867
|
+
chainId,
|
|
5868
|
+
gatewayChainId,
|
|
5869
|
+
bits: zkProof.bits,
|
|
5870
|
+
coprocessorSigners,
|
|
5871
|
+
extraData: '0x00',
|
|
5872
|
+
thresholdCoprocessorSigners,
|
|
5873
|
+
relayerProvider: relayerFhevm.relayerProvider,
|
|
5874
|
+
verifyingContractAddressInputVerification: verifyingContractAddressInputVerification,
|
|
5875
|
+
options,
|
|
5876
|
+
});
|
|
5877
|
+
},
|
|
4995
5878
|
generateKeypair,
|
|
4996
5879
|
createEIP712: createEIP712(verifyingContractAddressDecryption, chainId),
|
|
4997
5880
|
publicDecrypt: publicDecryptRequest(kmsSigners, thresholdKMSSigners, gatewayChainId, verifyingContractAddressDecryption, aclContractAddress,
|
|
@@ -5001,7 +5884,7 @@ const createInstance = async (config) => {
|
|
|
5001
5884
|
//cleanURL(config.relayerUrl),
|
|
5002
5885
|
relayerFhevm.relayerProvider, provider, auth && { auth }),
|
|
5003
5886
|
getPublicKey: () => relayerFhevm.getPublicKeyBytes(),
|
|
5004
|
-
getPublicParams: (bits) => relayerFhevm.
|
|
5887
|
+
getPublicParams: (bits) => relayerFhevm.getPublicParamsBytesForBits(bits),
|
|
5005
5888
|
// getPublicKey: () =>
|
|
5006
5889
|
// publicKeyData.publicKey
|
|
5007
5890
|
// ? {
|
|
@@ -5039,10 +5922,10 @@ const createTfheKeypair = () => {
|
|
|
5039
5922
|
};
|
|
5040
5923
|
const createTfhePublicKey = () => {
|
|
5041
5924
|
const { publicKey } = createTfheKeypair();
|
|
5042
|
-
return
|
|
5925
|
+
return bytesToHexNo0x(publicKey.serialize());
|
|
5043
5926
|
};
|
|
5044
5927
|
|
|
5045
5928
|
global.TFHE = TFHEPkg;
|
|
5046
5929
|
global.TKMS = TKMSPkg;
|
|
5047
5930
|
|
|
5048
|
-
export {
|
|
5931
|
+
export { MainnetConfig, SepoliaConfig, createEIP712, createInstance, createTfheKeypair, createTfhePublicKey, generateKeypair, getErrorCauseCode, getErrorCauseStatus };
|