@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.cjs
CHANGED
|
@@ -28,31 +28,9 @@ const SERIALIZED_SIZE_LIMIT_CIPHERTEXT = BigInt(1024 * 1024 * 512);
|
|
|
28
28
|
const SERIALIZED_SIZE_LIMIT_PK = BigInt(1024 * 1024 * 512);
|
|
29
29
|
const SERIALIZED_SIZE_LIMIT_CRS = BigInt(1024 * 1024 * 512);
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
case 'BearerToken':
|
|
35
|
-
init.headers['Authorization'] =
|
|
36
|
-
`Bearer ${auth.token}`;
|
|
37
|
-
break;
|
|
38
|
-
case 'ApiKeyHeader':
|
|
39
|
-
init.headers[auth.header || 'x-api-key'] =
|
|
40
|
-
auth.value;
|
|
41
|
-
break;
|
|
42
|
-
case 'ApiKeyCookie':
|
|
43
|
-
if (typeof window !== 'undefined') {
|
|
44
|
-
document.cookie = `${auth.cookie || 'x-api-key'}=${auth.value}; path=/; SameSite=Lax; Secure; HttpOnly;`;
|
|
45
|
-
init.credentials = 'include';
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
let cookie = `${auth.cookie || 'x-api-key'}=${auth.value};`;
|
|
49
|
-
init.headers['Cookie'] = cookie;
|
|
50
|
-
}
|
|
51
|
-
break;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
return init;
|
|
55
|
-
}
|
|
31
|
+
// This file is auto-generated
|
|
32
|
+
const version = '0.4.0-alpha.2';
|
|
33
|
+
const sdkName = '@zama-fhe/relayer-sdk';
|
|
56
34
|
|
|
57
35
|
function getErrorCause(e) {
|
|
58
36
|
if (e instanceof Error && typeof e.cause === 'object' && e.cause !== null) {
|
|
@@ -234,7 +212,39 @@ function throwRelayerUnknownError(operation, error, message) {
|
|
|
234
212
|
});
|
|
235
213
|
}
|
|
236
214
|
|
|
237
|
-
|
|
215
|
+
/**
|
|
216
|
+
* Set the authentication method for the request. The default is no authentication.
|
|
217
|
+
* It supports:
|
|
218
|
+
* - Bearer Token
|
|
219
|
+
* - Custom header
|
|
220
|
+
* - Custom cookie
|
|
221
|
+
*/
|
|
222
|
+
function setAuth(init, auth) {
|
|
223
|
+
if (auth) {
|
|
224
|
+
switch (auth.__type) {
|
|
225
|
+
case 'BearerToken':
|
|
226
|
+
init.headers['Authorization'] =
|
|
227
|
+
`Bearer ${auth.token}`;
|
|
228
|
+
break;
|
|
229
|
+
case 'ApiKeyHeader':
|
|
230
|
+
init.headers[auth.header || 'x-api-key'] =
|
|
231
|
+
auth.value;
|
|
232
|
+
break;
|
|
233
|
+
case 'ApiKeyCookie':
|
|
234
|
+
if (typeof window !== 'undefined') {
|
|
235
|
+
document.cookie = `${auth.cookie || 'x-api-key'}=${auth.value}; path=/; SameSite=Lax; Secure; HttpOnly;`;
|
|
236
|
+
init.credentials = 'include';
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
let cookie = `${auth.cookie || 'x-api-key'}=${auth.value};`;
|
|
240
|
+
init.headers['Cookie'] = cookie;
|
|
241
|
+
}
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return init;
|
|
246
|
+
}
|
|
247
|
+
|
|
238
248
|
function assertIsRelayerV1FetchResponseJson(json) {
|
|
239
249
|
if (!json || typeof json !== 'object') {
|
|
240
250
|
throw new Error('Unexpected response JSON.');
|
|
@@ -245,11 +255,13 @@ function assertIsRelayerV1FetchResponseJson(json) {
|
|
|
245
255
|
throw new Error("Unexpected response JSON format: missing 'response' property.");
|
|
246
256
|
}
|
|
247
257
|
}
|
|
248
|
-
async function
|
|
258
|
+
async function fetchRelayerV1Post(relayerOperation, url, payload, options) {
|
|
249
259
|
const init = setAuth({
|
|
250
260
|
method: 'POST',
|
|
251
261
|
headers: {
|
|
252
262
|
'Content-Type': 'application/json',
|
|
263
|
+
'ZAMA-SDK-VERSION': `${version}`,
|
|
264
|
+
'ZAMA-SDK-NAME': `${sdkName}`,
|
|
253
265
|
},
|
|
254
266
|
body: JSON.stringify(payload),
|
|
255
267
|
}, options?.auth);
|
|
@@ -280,14 +292,20 @@ async function fetchRelayerJsonRpcPost(relayerOperation, url, payload, options)
|
|
|
280
292
|
}
|
|
281
293
|
return json;
|
|
282
294
|
}
|
|
283
|
-
async function
|
|
295
|
+
async function fetchRelayerV1Get(relayerOperation, url) {
|
|
296
|
+
const init = {
|
|
297
|
+
method: 'GET',
|
|
298
|
+
headers: {
|
|
299
|
+
'ZAMA-SDK-VERSION': `${version}`,
|
|
300
|
+
'ZAMA-SDK-NAME': `${sdkName}`,
|
|
301
|
+
},
|
|
302
|
+
};
|
|
284
303
|
let response;
|
|
285
304
|
let json;
|
|
286
305
|
try {
|
|
287
|
-
response = await fetch(url);
|
|
306
|
+
response = await fetch(url, init);
|
|
288
307
|
}
|
|
289
308
|
catch (e) {
|
|
290
|
-
console.log(e);
|
|
291
309
|
throwRelayerUnknownError(relayerOperation, e);
|
|
292
310
|
}
|
|
293
311
|
if (!response.ok) {
|
|
@@ -315,7 +333,7 @@ const getKeysFromRelayer = async (versionUrl, publicKeyId) => {
|
|
|
315
333
|
if (keyurlCache[versionUrl]) {
|
|
316
334
|
return keyurlCache[versionUrl];
|
|
317
335
|
}
|
|
318
|
-
const data = await
|
|
336
|
+
const data = await fetchRelayerV1Get('KEY_URL', `${versionUrl}/keyurl`);
|
|
319
337
|
try {
|
|
320
338
|
let pubKeyUrl;
|
|
321
339
|
// If no publicKeyId is provided, use the first one
|
|
@@ -404,7 +422,7 @@ class RelayerErrorBase extends Error {
|
|
|
404
422
|
_docsPath;
|
|
405
423
|
_docsUrl;
|
|
406
424
|
_version;
|
|
407
|
-
static VERSION =
|
|
425
|
+
static VERSION = version;
|
|
408
426
|
static DEFAULT_DOCS_BASE_URL = 'https//docs.zama.org';
|
|
409
427
|
static FULL_VERSION = `@zama-fhe/relayer-sdk@${RelayerErrorBase.VERSION}`;
|
|
410
428
|
constructor(params) {
|
|
@@ -813,6 +831,14 @@ function assertRecordStringArrayProperty(o, property, objName) {
|
|
|
813
831
|
}
|
|
814
832
|
}
|
|
815
833
|
}
|
|
834
|
+
function safeJSONstringify(o, space) {
|
|
835
|
+
try {
|
|
836
|
+
return JSON.stringify(o, (_, v) => (typeof v === 'bigint' ? v.toString() : v), space);
|
|
837
|
+
}
|
|
838
|
+
catch {
|
|
839
|
+
return '';
|
|
840
|
+
}
|
|
841
|
+
}
|
|
816
842
|
|
|
817
843
|
const abiKmsVerifier = [
|
|
818
844
|
'function getKmsSigners() view returns (address[])',
|
|
@@ -912,6 +938,7 @@ const getCoprocessorSignersThreshold = async (provider, inputVerifierContractAdd
|
|
|
912
938
|
return Number(threshold); // threshold is always supposed to fit in a number
|
|
913
939
|
};
|
|
914
940
|
|
|
941
|
+
// This file contains common utilities for both user and public decryption requests
|
|
915
942
|
const NumEncryptedBits = {
|
|
916
943
|
0: 2, // ebool
|
|
917
944
|
2: 8, // euint8
|
|
@@ -922,17 +949,17 @@ const NumEncryptedBits = {
|
|
|
922
949
|
7: 160, // eaddress
|
|
923
950
|
8: 256, // euint256
|
|
924
951
|
};
|
|
925
|
-
function getHandleType(handle) {
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
}
|
|
952
|
+
// export function getHandleType(handle: `0x${string}`): number {
|
|
953
|
+
// if (handle.length !== 66) {
|
|
954
|
+
// throw new Error(`Handle ${handle} is not of valid length`);
|
|
955
|
+
// }
|
|
956
|
+
// const hexPair = handle.slice(-4, -2).toLowerCase();
|
|
957
|
+
// const typeDiscriminant = parseInt(hexPair, 16);
|
|
958
|
+
// if (!(typeDiscriminant in NumEncryptedBits)) {
|
|
959
|
+
// throw new Error(`Handle ${handle} is not of valid type`);
|
|
960
|
+
// }
|
|
961
|
+
// return typeDiscriminant;
|
|
962
|
+
// }
|
|
936
963
|
function checkEncryptedBits(handles) {
|
|
937
964
|
let total = 0;
|
|
938
965
|
for (const handle of handles) {
|
|
@@ -990,7 +1017,7 @@ function isBytes(value, bytewidth) {
|
|
|
990
1017
|
if (!(value instanceof Uint8Array)) {
|
|
991
1018
|
return false;
|
|
992
1019
|
}
|
|
993
|
-
return value.length === bytewidth ;
|
|
1020
|
+
return bytewidth ? value.length === bytewidth : true;
|
|
994
1021
|
}
|
|
995
1022
|
function isBytesHex(value, bytewidth) {
|
|
996
1023
|
if (!is0x(value)) {
|
|
@@ -1223,6 +1250,54 @@ function assertUint8ArrayProperty(o, property, objName) {
|
|
|
1223
1250
|
});
|
|
1224
1251
|
}
|
|
1225
1252
|
}
|
|
1253
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1254
|
+
// Hex
|
|
1255
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1256
|
+
const HEX_CHARS = {
|
|
1257
|
+
'0': 0,
|
|
1258
|
+
'1': 1,
|
|
1259
|
+
'2': 2,
|
|
1260
|
+
'3': 3,
|
|
1261
|
+
'4': 4,
|
|
1262
|
+
'5': 5,
|
|
1263
|
+
'6': 6,
|
|
1264
|
+
'7': 7,
|
|
1265
|
+
'8': 8,
|
|
1266
|
+
'9': 9,
|
|
1267
|
+
a: 10,
|
|
1268
|
+
b: 11,
|
|
1269
|
+
c: 12,
|
|
1270
|
+
d: 13,
|
|
1271
|
+
e: 14,
|
|
1272
|
+
f: 15,
|
|
1273
|
+
A: 10,
|
|
1274
|
+
B: 11,
|
|
1275
|
+
C: 12,
|
|
1276
|
+
D: 13,
|
|
1277
|
+
E: 14,
|
|
1278
|
+
F: 15,
|
|
1279
|
+
};
|
|
1280
|
+
Object.freeze(HEX_CHARS);
|
|
1281
|
+
const HEX_BYTES = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'));
|
|
1282
|
+
Object.freeze(HEX_BYTES);
|
|
1283
|
+
const HEX_CHARS_CODES = new Uint8Array([
|
|
1284
|
+
48,
|
|
1285
|
+
49,
|
|
1286
|
+
50,
|
|
1287
|
+
51,
|
|
1288
|
+
52,
|
|
1289
|
+
53,
|
|
1290
|
+
54,
|
|
1291
|
+
55,
|
|
1292
|
+
56,
|
|
1293
|
+
57, // '0'-'9'
|
|
1294
|
+
97,
|
|
1295
|
+
98,
|
|
1296
|
+
99,
|
|
1297
|
+
100,
|
|
1298
|
+
101,
|
|
1299
|
+
102, // 'a'-'f'
|
|
1300
|
+
]);
|
|
1226
1301
|
/**
|
|
1227
1302
|
* Convert a Uint8Array to a hex string (without 0x prefix).
|
|
1228
1303
|
*/
|
|
@@ -1242,15 +1317,49 @@ function bytesToHexNo0x(bytes) {
|
|
|
1242
1317
|
function bytesToHex(bytes) {
|
|
1243
1318
|
return `0x${bytesToHexNo0x(bytes)}`;
|
|
1244
1319
|
}
|
|
1320
|
+
function bytesToHexLarge(bytes) {
|
|
1321
|
+
const out = new Uint8Array(2 + bytes.length * 2);
|
|
1322
|
+
out[0] = 48; // '0'
|
|
1323
|
+
out[1] = 120; // 'x'
|
|
1324
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
1325
|
+
const j = 2 + i * 2;
|
|
1326
|
+
out[j] = HEX_CHARS_CODES[bytes[i] >> 4];
|
|
1327
|
+
out[j + 1] = HEX_CHARS_CODES[bytes[i] & 0xf];
|
|
1328
|
+
}
|
|
1329
|
+
return new TextDecoder().decode(out);
|
|
1330
|
+
}
|
|
1245
1331
|
/**
|
|
1246
1332
|
* Convert a hex string prefixed by 0x or not to a Uint8Array
|
|
1333
|
+
* Any invalid byte string is converted to 0
|
|
1334
|
+
* "0xzzff" = [0, 255]
|
|
1335
|
+
* "0xzfff" = [0, 255]
|
|
1247
1336
|
*/
|
|
1248
1337
|
function hexToBytes(hexString) {
|
|
1338
|
+
if (hexString.length % 2 !== 0) {
|
|
1339
|
+
throw new Error('Invalid hex string: odd length');
|
|
1340
|
+
}
|
|
1249
1341
|
const arr = hexString.replace(/^(0x)/, '').match(/.{1,2}/g);
|
|
1250
1342
|
if (!arr)
|
|
1251
1343
|
return new Uint8Array();
|
|
1252
1344
|
return Uint8Array.from(arr.map((byte) => parseInt(byte, 16)));
|
|
1253
1345
|
}
|
|
1346
|
+
function hexToBytesFaster(hexString, strict = false) {
|
|
1347
|
+
const offset = hexString[0] === '0' && hexString[1] === 'x' ? 2 : 0;
|
|
1348
|
+
const len = hexString.length - offset;
|
|
1349
|
+
if (len % 2 !== 0) {
|
|
1350
|
+
throw new Error('Invalid hex string: odd length');
|
|
1351
|
+
}
|
|
1352
|
+
const bytes = new Uint8Array(len / 2);
|
|
1353
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
1354
|
+
const hi = HEX_CHARS[hexString[offset + i * 2]];
|
|
1355
|
+
const lo = HEX_CHARS[hexString[offset + i * 2 + 1]];
|
|
1356
|
+
if ((hi === undefined || lo === undefined) && strict) {
|
|
1357
|
+
throw new Error(`Invalid hex character at position ${offset + i * 2}`);
|
|
1358
|
+
}
|
|
1359
|
+
bytes[i] = (hi << 4) | lo;
|
|
1360
|
+
}
|
|
1361
|
+
return bytes;
|
|
1362
|
+
}
|
|
1254
1363
|
/**
|
|
1255
1364
|
* Convert a Uint8Array to a bigint
|
|
1256
1365
|
*/
|
|
@@ -1264,9 +1373,6 @@ function bytesToBigInt(byteArray) {
|
|
|
1264
1373
|
}
|
|
1265
1374
|
return result;
|
|
1266
1375
|
}
|
|
1267
|
-
function toHexString(bytes, with0x = false) {
|
|
1268
|
-
return `${with0x ? '0x' : ''}${bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '')}`;
|
|
1269
|
-
}
|
|
1270
1376
|
async function fetchBytes(url) {
|
|
1271
1377
|
const response = await fetch(url);
|
|
1272
1378
|
if (!response.ok) {
|
|
@@ -1342,9 +1448,7 @@ function checkDeadlineValidity(startTimestamp, durationDays) {
|
|
|
1342
1448
|
throw Error('User decrypt request has expired');
|
|
1343
1449
|
}
|
|
1344
1450
|
}
|
|
1345
|
-
const userDecryptRequest = (kmsSigners, gatewayChainId, chainId, verifyingContractAddress, aclContractAddress,
|
|
1346
|
-
//relayerUrl: string,
|
|
1347
|
-
relayerProvider, provider, instanceOptions) => async (_handles, privateKey, publicKey, signature, contractAddresses, userAddress, startTimestamp, durationDays, options) => {
|
|
1451
|
+
const userDecryptRequest = (kmsSigners, gatewayChainId, chainId, verifyingContractAddress, aclContractAddress, relayerProvider, provider, defaultOptions) => async (_handles, privateKey, publicKey, signature, contractAddresses, userAddress, startTimestamp, durationDays, options) => {
|
|
1348
1452
|
const extraData = '0x00';
|
|
1349
1453
|
let pubKey;
|
|
1350
1454
|
let privKey;
|
|
@@ -1358,16 +1462,16 @@ relayerProvider, provider, instanceOptions) => async (_handles, privateKey, publ
|
|
|
1358
1462
|
// Casting handles if string
|
|
1359
1463
|
const signatureSanitized = signature.replace(/^(0x)/, '');
|
|
1360
1464
|
const publicKeySanitized = publicKey.replace(/^(0x)/, '');
|
|
1361
|
-
const
|
|
1465
|
+
const handleContractPairs = _handles.map((h) => ({
|
|
1362
1466
|
handle: typeof h.handle === 'string'
|
|
1363
|
-
?
|
|
1364
|
-
:
|
|
1467
|
+
? bytesToHex(hexToBytes(h.handle))
|
|
1468
|
+
: bytesToHex(h.handle),
|
|
1365
1469
|
contractAddress: getAddress$1(h.contractAddress),
|
|
1366
1470
|
}));
|
|
1367
|
-
checkEncryptedBits(
|
|
1471
|
+
checkEncryptedBits(handleContractPairs.map((h) => h.handle));
|
|
1368
1472
|
checkDeadlineValidity(BigInt(startTimestamp), BigInt(durationDays));
|
|
1369
|
-
const acl = new ethers.
|
|
1370
|
-
const verifications =
|
|
1473
|
+
const acl = new ethers.Contract(aclContractAddress, aclABI$1, provider);
|
|
1474
|
+
const verifications = handleContractPairs.map(async ({ handle, contractAddress }) => {
|
|
1371
1475
|
const userAllowed = await acl.persistAllowed(handle, userAddress);
|
|
1372
1476
|
const contractAllowed = await acl.persistAllowed(handle, contractAddress);
|
|
1373
1477
|
if (!userAllowed) {
|
|
@@ -1391,7 +1495,7 @@ relayerProvider, provider, instanceOptions) => async (_handles, privateKey, publ
|
|
|
1391
1495
|
throw e;
|
|
1392
1496
|
});
|
|
1393
1497
|
const payloadForRequest = {
|
|
1394
|
-
handleContractPairs
|
|
1498
|
+
handleContractPairs,
|
|
1395
1499
|
requestValidity: {
|
|
1396
1500
|
startTimestamp: startTimestamp.toString(), // Convert to string
|
|
1397
1501
|
durationDays: durationDays.toString(), // Convert to string
|
|
@@ -1403,13 +1507,10 @@ relayerProvider, provider, instanceOptions) => async (_handles, privateKey, publ
|
|
|
1403
1507
|
publicKey: publicKeySanitized,
|
|
1404
1508
|
extraData,
|
|
1405
1509
|
};
|
|
1406
|
-
const json = await relayerProvider.fetchPostUserDecrypt(payloadForRequest,
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
// payloadForRequest,
|
|
1411
|
-
// instanceOptions ?? options,
|
|
1412
|
-
// );
|
|
1510
|
+
const json = await relayerProvider.fetchPostUserDecrypt(payloadForRequest, {
|
|
1511
|
+
...defaultOptions,
|
|
1512
|
+
...options,
|
|
1513
|
+
});
|
|
1413
1514
|
// assume the KMS Signers have the correct order
|
|
1414
1515
|
let indexedKmsSigners = kmsSigners.map((signer, index) => {
|
|
1415
1516
|
return TKMS.new_server_id_addr(index + 1, signer);
|
|
@@ -1431,13 +1532,13 @@ relayerProvider, provider, instanceOptions) => async (_handles, privateKey, publ
|
|
|
1431
1532
|
signature: signatureSanitized,
|
|
1432
1533
|
client_address: userAddress,
|
|
1433
1534
|
enc_key: publicKeySanitized,
|
|
1434
|
-
ciphertext_handles:
|
|
1535
|
+
ciphertext_handles: handleContractPairs.map((h) => h.handle.replace(/^0x/, '')),
|
|
1435
1536
|
eip712_verifying_contract: verifyingContractAddress,
|
|
1436
1537
|
};
|
|
1437
1538
|
const decryption = TKMS.process_user_decryption_resp_from_js(client, payloadForVerification, eip712Domain, json, //json.response,
|
|
1438
1539
|
pubKey, privKey, true);
|
|
1439
1540
|
const listBigIntDecryptions = decryption.map((d) => bytesToBigInt(d.bytes));
|
|
1440
|
-
const results = buildUserDecryptResults(
|
|
1541
|
+
const results = buildUserDecryptResults(handleContractPairs.map((h) => h.handle), listBigIntDecryptions);
|
|
1441
1542
|
return results;
|
|
1442
1543
|
}
|
|
1443
1544
|
catch (e) {
|
|
@@ -1580,9 +1681,8 @@ const createEncryptedInput = ({ aclContractAddress, chainId, tfheCompactPublicKe
|
|
|
1580
1681
|
|
|
1581
1682
|
const MAX_UINT64 = BigInt('18446744073709551615'); // 2^64 - 1
|
|
1582
1683
|
BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff');
|
|
1583
|
-
const MAX_UINT32 = 0xffffffff;
|
|
1584
1684
|
const MAX_UINT8 = 0xff;
|
|
1585
|
-
function
|
|
1685
|
+
function numberToHexNo0x(num) {
|
|
1586
1686
|
let hex = num.toString(16);
|
|
1587
1687
|
return hex.length % 2 ? '0' + hex : hex;
|
|
1588
1688
|
}
|
|
@@ -1616,25 +1716,19 @@ function isUint8(value) {
|
|
|
1616
1716
|
}
|
|
1617
1717
|
return value <= MAX_UINT8;
|
|
1618
1718
|
}
|
|
1619
|
-
function isUint32(value) {
|
|
1620
|
-
if (!isUint(value)) {
|
|
1621
|
-
return false;
|
|
1622
|
-
}
|
|
1623
|
-
return value <= MAX_UINT32;
|
|
1624
|
-
}
|
|
1625
1719
|
function isUint64(value) {
|
|
1626
1720
|
if (!isUint(value)) {
|
|
1627
1721
|
return false;
|
|
1628
1722
|
}
|
|
1629
1723
|
return value <= MAX_UINT64;
|
|
1630
1724
|
}
|
|
1631
|
-
function
|
|
1632
|
-
if (!
|
|
1633
|
-
throw new InvalidTypeError({ expectedType: '
|
|
1725
|
+
function numberToBytes32(num) {
|
|
1726
|
+
if (!isUintNumber(num)) {
|
|
1727
|
+
throw new InvalidTypeError({ expectedType: 'Uint' });
|
|
1634
1728
|
}
|
|
1635
1729
|
const buffer = new ArrayBuffer(32);
|
|
1636
1730
|
const view = new DataView(buffer);
|
|
1637
|
-
view.
|
|
1731
|
+
view.setBigUint64(24, BigInt(num), false);
|
|
1638
1732
|
return new Uint8Array(buffer);
|
|
1639
1733
|
}
|
|
1640
1734
|
function assertIsUint8(value) {
|
|
@@ -1729,47 +1823,216 @@ function checksummedAddressToBytes20(address) {
|
|
|
1729
1823
|
return bytes;
|
|
1730
1824
|
}
|
|
1731
1825
|
|
|
1826
|
+
class FhevmHandleError extends RelayerErrorBase {
|
|
1827
|
+
constructor({ handle, message }) {
|
|
1828
|
+
super({
|
|
1829
|
+
message: message ??
|
|
1830
|
+
(handle
|
|
1831
|
+
? `FHEVM Handle "${handle}" is invalid.`
|
|
1832
|
+
: `FHEVM Handle is invalid.`),
|
|
1833
|
+
name: 'FhevmHandleError',
|
|
1834
|
+
});
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1838
|
+
class FheTypeError extends RelayerErrorBase {
|
|
1839
|
+
constructor({ fheTypeId, message, }) {
|
|
1840
|
+
super({
|
|
1841
|
+
message: message ??
|
|
1842
|
+
(fheTypeId
|
|
1843
|
+
? `FheTypeId "${fheTypeId}" is invalid.`
|
|
1844
|
+
: `FheTypeId is invalid.`),
|
|
1845
|
+
name: 'FheTypeError',
|
|
1846
|
+
});
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1850
|
+
const FheTypeIdToName = {
|
|
1851
|
+
0: 'ebool',
|
|
1852
|
+
//1: 'euint4', has been deprecated
|
|
1853
|
+
2: 'euint8',
|
|
1854
|
+
3: 'euint16',
|
|
1855
|
+
4: 'euint32',
|
|
1856
|
+
5: 'euint64',
|
|
1857
|
+
6: 'euint128',
|
|
1858
|
+
7: 'eaddress',
|
|
1859
|
+
8: 'euint256',
|
|
1860
|
+
};
|
|
1861
|
+
const FheTypeIdToEncryptionBitwidth = {
|
|
1862
|
+
0: 2,
|
|
1863
|
+
//1:?, euint4 has been deprecated
|
|
1864
|
+
2: 8,
|
|
1865
|
+
3: 16,
|
|
1866
|
+
4: 32,
|
|
1867
|
+
5: 64,
|
|
1868
|
+
6: 128,
|
|
1869
|
+
7: 160,
|
|
1870
|
+
8: 256,
|
|
1871
|
+
};
|
|
1872
|
+
const EncryptionBitwidthToFheTypeId = {
|
|
1873
|
+
2: 0,
|
|
1874
|
+
//?:1, euint4 has been deprecated
|
|
1875
|
+
8: 2,
|
|
1876
|
+
16: 3,
|
|
1877
|
+
32: 4,
|
|
1878
|
+
64: 5,
|
|
1879
|
+
128: 6,
|
|
1880
|
+
160: 7,
|
|
1881
|
+
256: 8,
|
|
1882
|
+
};
|
|
1883
|
+
const FheTypeIdToSolidityPrimitiveTypeName = {
|
|
1884
|
+
0: 'bool',
|
|
1885
|
+
//1:'uint256', euint4 has been deprecated
|
|
1886
|
+
2: 'uint256',
|
|
1887
|
+
3: 'uint256',
|
|
1888
|
+
4: 'uint256',
|
|
1889
|
+
5: 'uint256',
|
|
1890
|
+
6: 'uint256',
|
|
1891
|
+
7: 'address',
|
|
1892
|
+
8: 'uint256',
|
|
1893
|
+
};
|
|
1894
|
+
Object.freeze(FheTypeIdToEncryptionBitwidth);
|
|
1895
|
+
Object.freeze(EncryptionBitwidthToFheTypeId);
|
|
1896
|
+
Object.freeze(FheTypeIdToSolidityPrimitiveTypeName);
|
|
1897
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1898
|
+
// Type Guards
|
|
1899
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1900
|
+
/**
|
|
1901
|
+
* Checks if a value is a valid FheTypeId.
|
|
1902
|
+
* @example isFheTypeId(2) // true (euint8)
|
|
1903
|
+
* @example isFheTypeId(1) // false (euint4 is deprecated)
|
|
1904
|
+
*/
|
|
1905
|
+
function isFheTypeId(value) {
|
|
1906
|
+
switch (value) {
|
|
1907
|
+
case 0:
|
|
1908
|
+
// 1: euint4 is deprecated
|
|
1909
|
+
case 2:
|
|
1910
|
+
case 3:
|
|
1911
|
+
case 4:
|
|
1912
|
+
case 5:
|
|
1913
|
+
case 6:
|
|
1914
|
+
case 7:
|
|
1915
|
+
case 8:
|
|
1916
|
+
return true;
|
|
1917
|
+
default:
|
|
1918
|
+
return false;
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1921
|
+
/**
|
|
1922
|
+
* Checks if a value is a valid encryption bit width.
|
|
1923
|
+
* @example isEncryptionBits(8) // true
|
|
1924
|
+
* @example isEncryptionBits(4) // false (euint4 is deprecated)
|
|
1925
|
+
*/
|
|
1926
|
+
function isEncryptionBits(value) {
|
|
1927
|
+
if (typeof value !== 'number') {
|
|
1928
|
+
return false;
|
|
1929
|
+
}
|
|
1930
|
+
return value in EncryptionBitwidthToFheTypeId;
|
|
1931
|
+
}
|
|
1932
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1933
|
+
// FheTypeId extractors
|
|
1934
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1935
|
+
/**
|
|
1936
|
+
* Converts an encryption bit width to its corresponding FheTypeId.
|
|
1937
|
+
* @throws {FheTypeError} If bitwidth is not a valid encryption bit width.
|
|
1938
|
+
* @example fheTypeIdFromEncryptionBits(8) // 2 (euint8)
|
|
1939
|
+
*/
|
|
1940
|
+
function fheTypeIdFromEncryptionBits(bitwidth) {
|
|
1941
|
+
if (!isEncryptionBits(bitwidth)) {
|
|
1942
|
+
throw new FheTypeError({
|
|
1943
|
+
message: `Invalid encryption bits ${bitwidth}`,
|
|
1944
|
+
});
|
|
1945
|
+
}
|
|
1946
|
+
return EncryptionBitwidthToFheTypeId[bitwidth];
|
|
1947
|
+
}
|
|
1948
|
+
/**
|
|
1949
|
+
* Converts an FheTypeId to its corresponding FheTypeName.
|
|
1950
|
+
* @throws {FheTypeError} If id is not a valid FheTypeId.
|
|
1951
|
+
* @example fheTypeNameFromId(2) // 'euint8'
|
|
1952
|
+
*/
|
|
1953
|
+
function fheTypeNameFromId(id) {
|
|
1954
|
+
if (!isFheTypeId(id)) {
|
|
1955
|
+
throw new FheTypeError({
|
|
1956
|
+
message: `Invalid FheType id '${id}'`,
|
|
1957
|
+
});
|
|
1958
|
+
}
|
|
1959
|
+
return FheTypeIdToName[id];
|
|
1960
|
+
}
|
|
1961
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1962
|
+
// Solidity primitive type names
|
|
1963
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1964
|
+
/**
|
|
1965
|
+
* Returns the Solidity primitive type name for an FheTypeId.
|
|
1966
|
+
* @example solidityPrimitiveTypeNameFromFheTypeId(0) // 'bool'
|
|
1967
|
+
* @example solidityPrimitiveTypeNameFromFheTypeId(7) // 'address'
|
|
1968
|
+
* @example solidityPrimitiveTypeNameFromFheTypeId(2) // 'uint256'
|
|
1969
|
+
*/
|
|
1970
|
+
function solidityPrimitiveTypeNameFromFheTypeId(typeId) {
|
|
1971
|
+
if (!isFheTypeId(typeId)) {
|
|
1972
|
+
throw new FheTypeError({
|
|
1973
|
+
message: `Invalid FheType id '${typeId}'`,
|
|
1974
|
+
});
|
|
1975
|
+
}
|
|
1976
|
+
return FheTypeIdToSolidityPrimitiveTypeName[typeId];
|
|
1977
|
+
}
|
|
1978
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1979
|
+
// Encryption Bits
|
|
1980
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1981
|
+
/**
|
|
1982
|
+
* Returns the encryption bit width for an FheTypeId.
|
|
1983
|
+
* @example encryptionBitsFromFheTypeId(2) // 8 (euint8)
|
|
1984
|
+
* @example encryptionBitsFromFheTypeId(7) // 160 (eaddress)
|
|
1985
|
+
*/
|
|
1986
|
+
function encryptionBitsFromFheTypeId(typeId) {
|
|
1987
|
+
if (!isFheTypeId(typeId)) {
|
|
1988
|
+
throw new FheTypeError({
|
|
1989
|
+
message: `Invalid FheType id '${typeId}'`,
|
|
1990
|
+
});
|
|
1991
|
+
}
|
|
1992
|
+
return FheTypeIdToEncryptionBitwidth[typeId];
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1732
1995
|
////////////////////////////////////////////////////////////////////////////////
|
|
1733
1996
|
// FhevmHandle
|
|
1734
1997
|
////////////////////////////////////////////////////////////////////////////////
|
|
1735
1998
|
class FhevmHandle {
|
|
1999
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2000
|
+
// Instance Properties
|
|
2001
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
1736
2002
|
_hash21;
|
|
1737
2003
|
_chainId;
|
|
1738
2004
|
_fheTypeId;
|
|
1739
2005
|
_version;
|
|
1740
2006
|
_computed;
|
|
1741
2007
|
_index;
|
|
2008
|
+
_handleBytes32Hex;
|
|
2009
|
+
_handleBytes32;
|
|
2010
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2011
|
+
// Static Constants
|
|
2012
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
1742
2013
|
static RAW_CT_HASH_DOMAIN_SEPARATOR = 'ZK-w_rct';
|
|
1743
2014
|
static HANDLE_HASH_DOMAIN_SEPARATOR = 'ZK-w_hdl';
|
|
1744
|
-
static
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
static FheTypeEncryptionBitwidthsToId = {
|
|
1755
|
-
2: 0,
|
|
1756
|
-
8: 2,
|
|
1757
|
-
16: 3,
|
|
1758
|
-
32: 4,
|
|
1759
|
-
64: 5,
|
|
1760
|
-
128: 6,
|
|
1761
|
-
160: 7,
|
|
1762
|
-
256: 8,
|
|
1763
|
-
};
|
|
1764
|
-
static {
|
|
1765
|
-
Object.freeze(FhevmHandle.FheTypeIdToEncryptionBitwidths);
|
|
1766
|
-
Object.freeze(FhevmHandle.FheTypeEncryptionBitwidthsToId);
|
|
1767
|
-
}
|
|
1768
|
-
constructor(hash21, chainId, fheTypeId, version, computed, index) {
|
|
2015
|
+
static CURRENT_CIPHERTEXT_VERSION = 0;
|
|
2016
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2017
|
+
// Constructor
|
|
2018
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2019
|
+
constructor({ hash21, chainId, fheTypeId, version, computed, index, handleBytes32, handleBytes32Hex, }) {
|
|
2020
|
+
if (!isUintNumber(chainId)) {
|
|
2021
|
+
throw new FhevmHandleError({
|
|
2022
|
+
message: 'ChainId must be a positive integer',
|
|
2023
|
+
});
|
|
2024
|
+
}
|
|
1769
2025
|
if (BigInt(chainId) > MAX_UINT64) {
|
|
1770
2026
|
// fhevm assumes chainID is only taking up to 8 bytes
|
|
1771
|
-
throw new
|
|
2027
|
+
throw new FhevmHandleError({
|
|
2028
|
+
message: 'ChainId exceeds maximum allowed value (8 bytes)',
|
|
2029
|
+
});
|
|
1772
2030
|
}
|
|
2031
|
+
if (!isBytesHex(hash21, 21)) {
|
|
2032
|
+
throw new FhevmHandleError({ message: 'Hash21 should be 21 bytes long' });
|
|
2033
|
+
}
|
|
2034
|
+
this._handleBytes32 = handleBytes32;
|
|
2035
|
+
this._handleBytes32Hex = handleBytes32Hex;
|
|
1773
2036
|
this._hash21 = hash21;
|
|
1774
2037
|
this._chainId = chainId;
|
|
1775
2038
|
this._fheTypeId = fheTypeId;
|
|
@@ -1779,6 +2042,9 @@ class FhevmHandle {
|
|
|
1779
2042
|
this._index = index;
|
|
1780
2043
|
}
|
|
1781
2044
|
}
|
|
2045
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2046
|
+
// Instance Getters
|
|
2047
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
1782
2048
|
get hash21() {
|
|
1783
2049
|
return this._hash21;
|
|
1784
2050
|
}
|
|
@@ -1788,6 +2054,9 @@ class FhevmHandle {
|
|
|
1788
2054
|
get fheTypeId() {
|
|
1789
2055
|
return this._fheTypeId;
|
|
1790
2056
|
}
|
|
2057
|
+
get fheTypeName() {
|
|
2058
|
+
return fheTypeNameFromId(this._fheTypeId);
|
|
2059
|
+
}
|
|
1791
2060
|
get version() {
|
|
1792
2061
|
return this._version;
|
|
1793
2062
|
}
|
|
@@ -1797,6 +2066,106 @@ class FhevmHandle {
|
|
|
1797
2066
|
get index() {
|
|
1798
2067
|
return this._index;
|
|
1799
2068
|
}
|
|
2069
|
+
get encryptedBitwidth() {
|
|
2070
|
+
return encryptionBitsFromFheTypeId(this._fheTypeId);
|
|
2071
|
+
}
|
|
2072
|
+
get solidityPrimitiveTypeName() {
|
|
2073
|
+
return solidityPrimitiveTypeNameFromFheTypeId(this._fheTypeId);
|
|
2074
|
+
}
|
|
2075
|
+
toJSON() {
|
|
2076
|
+
return {
|
|
2077
|
+
handle: this.toBytes32Hex(),
|
|
2078
|
+
fheTypeName: this.fheTypeName,
|
|
2079
|
+
fheTypeId: this.fheTypeId,
|
|
2080
|
+
chainId: this.chainId,
|
|
2081
|
+
index: this.index,
|
|
2082
|
+
computed: this.computed,
|
|
2083
|
+
encryptedBitwidth: this.encryptedBitwidth,
|
|
2084
|
+
version: this.version,
|
|
2085
|
+
solidityPrimitiveTypeName: this.solidityPrimitiveTypeName,
|
|
2086
|
+
hash21: this.hash21,
|
|
2087
|
+
};
|
|
2088
|
+
}
|
|
2089
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2090
|
+
// Instance Serialization
|
|
2091
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2092
|
+
toBytes32() {
|
|
2093
|
+
if (this._handleBytes32 === undefined) {
|
|
2094
|
+
assertRelayer((this._index === undefined && this._computed) ||
|
|
2095
|
+
(this._index !== undefined && this._index < 255 && !this._computed));
|
|
2096
|
+
const chainId32Bytes = numberToBytes32(this._chainId);
|
|
2097
|
+
const chainId8Bytes = chainId32Bytes.subarray(24, 32);
|
|
2098
|
+
const handleHash21 = hexToBytes(this._hash21);
|
|
2099
|
+
assertRelayer(handleHash21.length === 21);
|
|
2100
|
+
const handleBytes32AsBytes = new Uint8Array(32);
|
|
2101
|
+
handleBytes32AsBytes.set(handleHash21, 0);
|
|
2102
|
+
handleBytes32AsBytes[21] = this._index === undefined ? 255 : this._index;
|
|
2103
|
+
handleBytes32AsBytes.set(chainId8Bytes, 22);
|
|
2104
|
+
handleBytes32AsBytes[30] = this._fheTypeId;
|
|
2105
|
+
handleBytes32AsBytes[31] = this._version;
|
|
2106
|
+
this._handleBytes32 = handleBytes32AsBytes;
|
|
2107
|
+
}
|
|
2108
|
+
return this._handleBytes32;
|
|
2109
|
+
}
|
|
2110
|
+
toBytes32Hex() {
|
|
2111
|
+
if (this._handleBytes32Hex === undefined) {
|
|
2112
|
+
this._handleBytes32Hex = bytesToHex(this.toBytes32());
|
|
2113
|
+
}
|
|
2114
|
+
return this._handleBytes32Hex;
|
|
2115
|
+
}
|
|
2116
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2117
|
+
// Static Factory Methods
|
|
2118
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2119
|
+
static fromComponents(params) {
|
|
2120
|
+
return new FhevmHandle(params);
|
|
2121
|
+
}
|
|
2122
|
+
static fromBytes32(handle) {
|
|
2123
|
+
if (!isBytes32(handle)) {
|
|
2124
|
+
throw new FhevmHandleError({
|
|
2125
|
+
message: `FHEVM Handle is not a valid bytes32 array.`,
|
|
2126
|
+
});
|
|
2127
|
+
}
|
|
2128
|
+
const bytes = handle;
|
|
2129
|
+
// Extract hash21 (bytes 0-20)
|
|
2130
|
+
const hash21 = bytesToHex(bytes.slice(0, 21));
|
|
2131
|
+
// Extract index (byte 21) - 255 means computed
|
|
2132
|
+
const indexByte = bytes[21];
|
|
2133
|
+
const computed = indexByte === 255;
|
|
2134
|
+
const index = computed ? undefined : indexByte;
|
|
2135
|
+
// Extract chainId (bytes 22-29, 8 bytes as big-endian uint64)
|
|
2136
|
+
let chainId = 0;
|
|
2137
|
+
for (let i = 22; i < 30; i++) {
|
|
2138
|
+
chainId = chainId * 256 + bytes[i];
|
|
2139
|
+
}
|
|
2140
|
+
// Extract fheTypeId (byte 30)
|
|
2141
|
+
const fheTypeIdByte = bytes[30];
|
|
2142
|
+
if (!isFheTypeId(fheTypeIdByte)) {
|
|
2143
|
+
throw new FhevmHandleError({
|
|
2144
|
+
handle,
|
|
2145
|
+
message: `FHEVM Handle "${handle}" is invalid. Unknown FheType: ${fheTypeIdByte}`,
|
|
2146
|
+
});
|
|
2147
|
+
}
|
|
2148
|
+
// Extract version (byte 31)
|
|
2149
|
+
const version = bytes[31];
|
|
2150
|
+
return new FhevmHandle({
|
|
2151
|
+
hash21,
|
|
2152
|
+
chainId,
|
|
2153
|
+
fheTypeId: fheTypeIdByte,
|
|
2154
|
+
version,
|
|
2155
|
+
computed,
|
|
2156
|
+
index,
|
|
2157
|
+
handleBytes32: handle,
|
|
2158
|
+
});
|
|
2159
|
+
}
|
|
2160
|
+
static fromBytes32Hex(handle) {
|
|
2161
|
+
if (!isBytes32Hex(handle)) {
|
|
2162
|
+
throw new FhevmHandleError({ handle });
|
|
2163
|
+
}
|
|
2164
|
+
const bytes = hexToBytes(handle);
|
|
2165
|
+
const h = FhevmHandle.fromBytes32(bytes);
|
|
2166
|
+
h._handleBytes32Hex = handle;
|
|
2167
|
+
return h;
|
|
2168
|
+
}
|
|
1800
2169
|
static fromZKProof(params) {
|
|
1801
2170
|
assertIsChecksummedAddress(params.aclAddress);
|
|
1802
2171
|
assertIsUint64(params.chainId);
|
|
@@ -1806,7 +2175,7 @@ class FhevmHandle {
|
|
|
1806
2175
|
fheTypeIds = params.fheTypeIds;
|
|
1807
2176
|
}
|
|
1808
2177
|
else if (params.fheTypeEncryptionBitwidths !== undefined) {
|
|
1809
|
-
fheTypeIds = params.fheTypeEncryptionBitwidths.map((w) =>
|
|
2178
|
+
fheTypeIds = params.fheTypeEncryptionBitwidths.map((w) => fheTypeIdFromEncryptionBits(w));
|
|
1810
2179
|
}
|
|
1811
2180
|
else {
|
|
1812
2181
|
throw new InternalError({
|
|
@@ -1837,22 +2206,69 @@ class FhevmHandle {
|
|
|
1837
2206
|
const handles = [];
|
|
1838
2207
|
for (let i = 0; i < fheTypeIds.length; ++i) {
|
|
1839
2208
|
const hash21 = FhevmHandle._computeInputHash21(hexToBytes(blobHashBytes32Hex), params.aclAddress, params.chainId, i);
|
|
1840
|
-
handles.push(new FhevmHandle(
|
|
2209
|
+
handles.push(new FhevmHandle({
|
|
2210
|
+
hash21,
|
|
2211
|
+
chainId: params.chainId,
|
|
2212
|
+
fheTypeId: fheTypeIds[i],
|
|
2213
|
+
version: params.ciphertextVersion,
|
|
2214
|
+
computed: false,
|
|
2215
|
+
index: i,
|
|
2216
|
+
}));
|
|
1841
2217
|
}
|
|
1842
2218
|
return handles;
|
|
1843
2219
|
}
|
|
2220
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2221
|
+
// Static Parsing
|
|
2222
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2223
|
+
static parse(handle) {
|
|
2224
|
+
if (isBytes(handle)) {
|
|
2225
|
+
return FhevmHandle.fromBytes32(handle);
|
|
2226
|
+
}
|
|
2227
|
+
return FhevmHandle.fromBytes32Hex(handle);
|
|
2228
|
+
}
|
|
2229
|
+
static canParse(handle) {
|
|
2230
|
+
try {
|
|
2231
|
+
FhevmHandle.parse(handle);
|
|
2232
|
+
return true;
|
|
2233
|
+
}
|
|
2234
|
+
catch {
|
|
2235
|
+
return false;
|
|
2236
|
+
}
|
|
2237
|
+
}
|
|
2238
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2239
|
+
// Static Assertions
|
|
2240
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2241
|
+
static assertIsHandleHex(handle) {
|
|
2242
|
+
if (typeof handle !== 'string') {
|
|
2243
|
+
throw new FhevmHandleError({
|
|
2244
|
+
message: 'Invalid bytes32 hexadecimal string',
|
|
2245
|
+
});
|
|
2246
|
+
}
|
|
2247
|
+
if (!FhevmHandle.canParse(handle)) {
|
|
2248
|
+
throw new FhevmHandleError({ handle });
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2252
|
+
// Static Helpers
|
|
2253
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2254
|
+
static currentCiphertextVersion() {
|
|
2255
|
+
return FhevmHandle.CURRENT_CIPHERTEXT_VERSION;
|
|
2256
|
+
}
|
|
2257
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2258
|
+
// Private Helpers
|
|
2259
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
1844
2260
|
/**
|
|
1845
2261
|
* blobHashBytes32 = keccak256(ciphertextWithZKProof)
|
|
1846
2262
|
*/
|
|
1847
2263
|
static _computeInputHash21(blobHashBytes32, aclAddress, chainId, index) {
|
|
1848
2264
|
/*
|
|
1849
2265
|
https://github.com/zama-ai/fhevm/blob/8ffbd5906ab3d57af178e049930e3fc065c9d4b3/coprocessor/fhevm-engine/zkproof-worker/src/verifier.rs#L431C7-L431C8
|
|
1850
|
-
|
|
2266
|
+
|
|
1851
2267
|
handle_hash = Bytes("ZK-w_hdl") + blobHash 32 Bytes + index 1 Byte + aclAddress 20 Bytes + chainId 32 bytes
|
|
1852
2268
|
===========================================================================================================
|
|
1853
2269
|
|
|
1854
2270
|
const HANDLE_HASH_DOMAIN_SEPARATOR: [u8; 8] = *b"ZK-w_hdl";
|
|
1855
|
-
|
|
2271
|
+
|
|
1856
2272
|
let mut handle_hash = Keccak256::new();
|
|
1857
2273
|
handle_hash.update(HANDLE_HASH_DOMAIN_SEPARATOR);
|
|
1858
2274
|
handle_hash.update(blob_hash);
|
|
@@ -1873,27 +2289,12 @@ class FhevmHandle {
|
|
|
1873
2289
|
assertIsUint64(chainId);
|
|
1874
2290
|
const encryptionIndexByte1 = new Uint8Array([index]);
|
|
1875
2291
|
const aclContractAddressBytes20 = checksummedAddressToBytes20(aclAddress);
|
|
1876
|
-
const chainIdBytes32 =
|
|
2292
|
+
const chainIdBytes32 = numberToBytes32(chainId);
|
|
1877
2293
|
const encoder = new TextEncoder();
|
|
1878
2294
|
const domainSepBytes = encoder.encode(FhevmHandle.HANDLE_HASH_DOMAIN_SEPARATOR);
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
assertRelayer((this._index === undefined && this._computed) ||
|
|
1883
|
-
(this._index !== undefined && this._index < 255 && !this._computed));
|
|
1884
|
-
const chainId32Bytes = uint32ToBytes32(this._chainId);
|
|
1885
|
-
const chainId8Bytes = chainId32Bytes.subarray(24, 32);
|
|
1886
|
-
const handleHash = hexToBytes(this._hash21);
|
|
1887
|
-
const handleBytes32AsBytes = new Uint8Array(32);
|
|
1888
|
-
handleBytes32AsBytes.set(handleHash, 0);
|
|
1889
|
-
handleBytes32AsBytes[21] = this._index === undefined ? 255 : this._index;
|
|
1890
|
-
handleBytes32AsBytes.set(chainId8Bytes, 22);
|
|
1891
|
-
handleBytes32AsBytes[30] = this._fheTypeId;
|
|
1892
|
-
handleBytes32AsBytes[31] = this._version;
|
|
1893
|
-
return handleBytes32AsBytes;
|
|
1894
|
-
}
|
|
1895
|
-
toBytes32Hex() {
|
|
1896
|
-
return bytesToHex(this.toBytes32());
|
|
2295
|
+
const hashBytes32Hex = ethers.keccak256(concatBytes(domainSepBytes, blobHashBytes32, encryptionIndexByte1, aclContractAddressBytes20, chainIdBytes32));
|
|
2296
|
+
// Truncate to 21 bytes (0x + 42 hex chars)
|
|
2297
|
+
return hashBytes32Hex.slice(0, 2 + 2 * 21);
|
|
1897
2298
|
}
|
|
1898
2299
|
}
|
|
1899
2300
|
|
|
@@ -1902,6 +2303,89 @@ const getAddress = (value) => ethers.getAddress(value);
|
|
|
1902
2303
|
const currentCiphertextVersion = () => {
|
|
1903
2304
|
return 0;
|
|
1904
2305
|
};
|
|
2306
|
+
async function requestCiphertextWithZKProofVerification({ bits, ciphertext, contractAddress, userAddress, aclContractAddress, verifyingContractAddressInputVerification, chainId, gatewayChainId, relayerProvider, coprocessorSigners, thresholdCoprocessorSigners, extraData, options, }) {
|
|
2307
|
+
const payload = {
|
|
2308
|
+
contractAddress,
|
|
2309
|
+
userAddress,
|
|
2310
|
+
ciphertextWithInputVerification: bytesToHexNo0x(ciphertext),
|
|
2311
|
+
contractChainId: ('0x' + chainId.toString(16)),
|
|
2312
|
+
extraData,
|
|
2313
|
+
};
|
|
2314
|
+
const json = await relayerProvider.fetchPostInputProof(payload, options);
|
|
2315
|
+
if (!isFhevmRelayerInputProofResponse(json)) {
|
|
2316
|
+
throwRelayerInternalError('INPUT_PROOF', json);
|
|
2317
|
+
}
|
|
2318
|
+
const fhevmHandles = FhevmHandle.fromZKProof({
|
|
2319
|
+
ciphertextWithZKProof: ciphertext,
|
|
2320
|
+
chainId,
|
|
2321
|
+
aclAddress: aclContractAddress,
|
|
2322
|
+
ciphertextVersion: currentCiphertextVersion(),
|
|
2323
|
+
fheTypeEncryptionBitwidths: bits,
|
|
2324
|
+
});
|
|
2325
|
+
const handles = fhevmHandles.map((h) => h.toBytes32());
|
|
2326
|
+
const result = json;
|
|
2327
|
+
// Note that the hex strings returned by the relayer do have have the 0x prefix
|
|
2328
|
+
if (result.handles && result.handles.length > 0) {
|
|
2329
|
+
const responseHandles = result.handles.map(hexToBytes);
|
|
2330
|
+
if (handles.length != responseHandles.length) {
|
|
2331
|
+
throw new Error(`Incorrect Handles list sizes: (expected) ${handles.length} != ${responseHandles.length} (received)`);
|
|
2332
|
+
}
|
|
2333
|
+
for (let index = 0; index < handles.length; index += 1) {
|
|
2334
|
+
let handle = handles[index];
|
|
2335
|
+
let responseHandle = responseHandles[index];
|
|
2336
|
+
let expected = bytesToHexNo0x(handle);
|
|
2337
|
+
let current = bytesToHexNo0x(responseHandle);
|
|
2338
|
+
if (expected !== current) {
|
|
2339
|
+
throw new Error(`Incorrect Handle ${index}: (expected) ${expected} != ${current} (received)`);
|
|
2340
|
+
}
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
const signatures = result.signatures;
|
|
2344
|
+
// verify signatures for inputs:
|
|
2345
|
+
const domain = {
|
|
2346
|
+
name: 'InputVerification',
|
|
2347
|
+
version: '1',
|
|
2348
|
+
chainId: gatewayChainId,
|
|
2349
|
+
verifyingContract: verifyingContractAddressInputVerification,
|
|
2350
|
+
};
|
|
2351
|
+
const types = {
|
|
2352
|
+
CiphertextVerification: [
|
|
2353
|
+
{ name: 'ctHandles', type: 'bytes32[]' },
|
|
2354
|
+
{ name: 'userAddress', type: 'address' },
|
|
2355
|
+
{ name: 'contractAddress', type: 'address' },
|
|
2356
|
+
{ name: 'contractChainId', type: 'uint256' },
|
|
2357
|
+
{ name: 'extraData', type: 'bytes' },
|
|
2358
|
+
],
|
|
2359
|
+
};
|
|
2360
|
+
const recoveredAddresses = signatures.map((signature) => {
|
|
2361
|
+
const sig = signature.startsWith('0x') ? signature : `0x${signature}`;
|
|
2362
|
+
const recoveredAddress = ethers.ethers.verifyTypedData(domain, types, {
|
|
2363
|
+
ctHandles: handles,
|
|
2364
|
+
userAddress,
|
|
2365
|
+
contractAddress,
|
|
2366
|
+
contractChainId: chainId,
|
|
2367
|
+
extraData,
|
|
2368
|
+
}, sig);
|
|
2369
|
+
return recoveredAddress;
|
|
2370
|
+
});
|
|
2371
|
+
const thresholdReached = isThresholdReached$1(coprocessorSigners, recoveredAddresses, thresholdCoprocessorSigners);
|
|
2372
|
+
if (!thresholdReached) {
|
|
2373
|
+
throw Error('Coprocessor signers threshold is not reached');
|
|
2374
|
+
}
|
|
2375
|
+
// inputProof is len(list_handles) + numCoprocessorSigners + list_handles + signatureCoprocessorSigners (1+1+NUM_HANDLES*32+65*numSigners)
|
|
2376
|
+
let inputProof = numberToHexNo0x(handles.length);
|
|
2377
|
+
const numSigners = signatures.length;
|
|
2378
|
+
inputProof += numberToHexNo0x(numSigners);
|
|
2379
|
+
const listHandlesStr = handles.map((i) => bytesToHexNo0x(i));
|
|
2380
|
+
listHandlesStr.map((handle) => (inputProof += handle));
|
|
2381
|
+
signatures.map((signature) => (inputProof += signature.slice(2))); // removes the '0x' prefix from the `signature` string
|
|
2382
|
+
// Append the extra data to the input proof
|
|
2383
|
+
inputProof += extraData.slice(2);
|
|
2384
|
+
return {
|
|
2385
|
+
handles,
|
|
2386
|
+
inputProof: hexToBytes(inputProof),
|
|
2387
|
+
};
|
|
2388
|
+
}
|
|
1905
2389
|
function isThresholdReached$1(coprocessorSigners, recoveredAddresses, threshold) {
|
|
1906
2390
|
const addressMap = new Map();
|
|
1907
2391
|
recoveredAddresses.forEach((address, index) => {
|
|
@@ -1933,9 +2417,7 @@ function isFhevmRelayerInputProofResponse(json) {
|
|
|
1933
2417
|
return (response.signatures.every((s) => typeof s === 'string') &&
|
|
1934
2418
|
response.handles.every((h) => typeof h === 'string'));
|
|
1935
2419
|
}
|
|
1936
|
-
const createRelayerEncryptedInput = (aclContractAddress, verifyingContractAddressInputVerification, chainId, gatewayChainId,
|
|
1937
|
-
//relayerUrl: string,
|
|
1938
|
-
relayerProvider, tfheCompactPublicKey, publicParams, coprocessorSigners, thresholdCoprocessorSigners, instanceOptions) => (contractAddress, userAddress) => {
|
|
2420
|
+
const createRelayerEncryptedInput = (aclContractAddress, verifyingContractAddressInputVerification, chainId, gatewayChainId, relayerProvider, tfheCompactPublicKey, publicParams, coprocessorSigners, thresholdCoprocessorSigners, defaultOptions) => (contractAddress, userAddress) => {
|
|
1939
2421
|
if (!ethers.isAddress(contractAddress)) {
|
|
1940
2422
|
throw new Error('Contract address is not a valid address.');
|
|
1941
2423
|
}
|
|
@@ -1987,25 +2469,31 @@ relayerProvider, tfheCompactPublicKey, publicParams, coprocessorSigners, thresho
|
|
|
1987
2469
|
getBits() {
|
|
1988
2470
|
return input.getBits();
|
|
1989
2471
|
},
|
|
2472
|
+
generateZKProof() {
|
|
2473
|
+
return {
|
|
2474
|
+
chainId,
|
|
2475
|
+
aclContractAddress: aclContractAddress,
|
|
2476
|
+
userAddress: userAddress,
|
|
2477
|
+
contractAddress: contractAddress,
|
|
2478
|
+
ciphertextWithZkProof: input.encrypt(),
|
|
2479
|
+
bits: input.getBits(),
|
|
2480
|
+
};
|
|
2481
|
+
},
|
|
1990
2482
|
encrypt: async (options) => {
|
|
1991
2483
|
const extraData = '0x00';
|
|
1992
2484
|
const bits = input.getBits();
|
|
1993
2485
|
const ciphertext = input.encrypt();
|
|
1994
|
-
//console.log(`ciphertext=${toHexString(ciphertext)}`);
|
|
1995
2486
|
const payload = {
|
|
1996
2487
|
contractAddress: getAddress(contractAddress),
|
|
1997
2488
|
userAddress: getAddress(userAddress),
|
|
1998
|
-
ciphertextWithInputVerification:
|
|
2489
|
+
ciphertextWithInputVerification: bytesToHexNo0x(ciphertext),
|
|
1999
2490
|
contractChainId: ('0x' + chainId.toString(16)),
|
|
2000
2491
|
extraData,
|
|
2001
2492
|
};
|
|
2002
|
-
const json = await relayerProvider.fetchPostInputProof(payload,
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
// payload,
|
|
2007
|
-
// options ?? instanceOptions,
|
|
2008
|
-
// );
|
|
2493
|
+
const json = await relayerProvider.fetchPostInputProof(payload, {
|
|
2494
|
+
...defaultOptions,
|
|
2495
|
+
...options,
|
|
2496
|
+
});
|
|
2009
2497
|
if (!isFhevmRelayerInputProofResponse(json)) {
|
|
2010
2498
|
throwRelayerInternalError('INPUT_PROOF', json);
|
|
2011
2499
|
}
|
|
@@ -2017,7 +2505,6 @@ relayerProvider, tfheCompactPublicKey, publicParams, coprocessorSigners, thresho
|
|
|
2017
2505
|
fheTypeEncryptionBitwidths: bits,
|
|
2018
2506
|
});
|
|
2019
2507
|
const handles = fhevmHandles.map((h) => h.toBytes32());
|
|
2020
|
-
//const result = json.response;
|
|
2021
2508
|
const result = json;
|
|
2022
2509
|
// Note that the hex strings returned by the relayer do have have the 0x prefix
|
|
2023
2510
|
if (result.handles && result.handles.length > 0) {
|
|
@@ -2028,8 +2515,8 @@ relayerProvider, tfheCompactPublicKey, publicParams, coprocessorSigners, thresho
|
|
|
2028
2515
|
for (let index = 0; index < handles.length; index += 1) {
|
|
2029
2516
|
let handle = handles[index];
|
|
2030
2517
|
let responseHandle = responseHandles[index];
|
|
2031
|
-
let expected =
|
|
2032
|
-
let current =
|
|
2518
|
+
let expected = bytesToHexNo0x(handle);
|
|
2519
|
+
let current = bytesToHexNo0x(responseHandle);
|
|
2033
2520
|
if (expected !== current) {
|
|
2034
2521
|
throw new Error(`Incorrect Handle ${index}: (expected) ${expected} != ${current} (received)`);
|
|
2035
2522
|
}
|
|
@@ -2068,10 +2555,10 @@ relayerProvider, tfheCompactPublicKey, publicParams, coprocessorSigners, thresho
|
|
|
2068
2555
|
throw Error('Coprocessor signers threshold is not reached');
|
|
2069
2556
|
}
|
|
2070
2557
|
// inputProof is len(list_handles) + numCoprocessorSigners + list_handles + signatureCoprocessorSigners (1+1+NUM_HANDLES*32+65*numSigners)
|
|
2071
|
-
let inputProof =
|
|
2558
|
+
let inputProof = numberToHexNo0x(handles.length);
|
|
2072
2559
|
const numSigners = signatures.length;
|
|
2073
|
-
inputProof +=
|
|
2074
|
-
const listHandlesStr = handles.map((i) =>
|
|
2560
|
+
inputProof += numberToHexNo0x(numSigners);
|
|
2561
|
+
const listHandlesStr = handles.map((i) => bytesToHexNo0x(i));
|
|
2075
2562
|
listHandlesStr.map((handle) => (inputProof += handle));
|
|
2076
2563
|
signatures.map((signature) => (inputProof += signature.slice(2))); // removes the '0x' prefix from the `signature` string
|
|
2077
2564
|
// Append the extra data to the input proof
|
|
@@ -2084,15 +2571,30 @@ relayerProvider, tfheCompactPublicKey, publicParams, coprocessorSigners, thresho
|
|
|
2084
2571
|
};
|
|
2085
2572
|
};
|
|
2086
2573
|
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
const
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2574
|
+
function ensureError(e) {
|
|
2575
|
+
if (e instanceof Error) {
|
|
2576
|
+
return e;
|
|
2577
|
+
}
|
|
2578
|
+
const message = e.message ?? 'Non-Error value caught in exception handler';
|
|
2579
|
+
const name = e.name ?? 'ErrorWrapper';
|
|
2580
|
+
const cause = e.cause ?? e;
|
|
2581
|
+
const err = new Error(message, { cause });
|
|
2582
|
+
err.name = name;
|
|
2583
|
+
return err;
|
|
2584
|
+
}
|
|
2585
|
+
function assertNever(value, message) {
|
|
2586
|
+
throw new InternalError({ message });
|
|
2587
|
+
}
|
|
2588
|
+
|
|
2589
|
+
const aclABI = [
|
|
2590
|
+
'function isAllowedForDecryption(bytes32 handle) view returns (bool)',
|
|
2591
|
+
];
|
|
2592
|
+
function isThresholdReached(kmsSigners, recoveredAddresses, threshold) {
|
|
2593
|
+
const addressMap = new Map();
|
|
2594
|
+
recoveredAddresses.forEach((address, index) => {
|
|
2595
|
+
if (addressMap.has(address)) {
|
|
2596
|
+
const duplicateValue = address;
|
|
2597
|
+
throw new Error(`Duplicate KMS signer address found: ${duplicateValue} appears multiple times in recovered addresses`);
|
|
2096
2598
|
}
|
|
2097
2599
|
addressMap.set(address, index);
|
|
2098
2600
|
});
|
|
@@ -2109,7 +2611,7 @@ function abiEncodeClearValues(clearValues) {
|
|
|
2109
2611
|
const abiValues = [];
|
|
2110
2612
|
for (let i = 0; i < handlesBytes32Hex.length; ++i) {
|
|
2111
2613
|
const handle = handlesBytes32Hex[i];
|
|
2112
|
-
const handleType =
|
|
2614
|
+
const handleType = FhevmHandle.parse(handle).fheTypeId;
|
|
2113
2615
|
let clearTextValue = clearValues[handle];
|
|
2114
2616
|
if (typeof clearTextValue === 'boolean') {
|
|
2115
2617
|
clearTextValue = clearTextValue ? '0x01' : '0x00';
|
|
@@ -2146,7 +2648,7 @@ function abiEncodeClearValues(clearValues) {
|
|
|
2146
2648
|
break;
|
|
2147
2649
|
}
|
|
2148
2650
|
default: {
|
|
2149
|
-
|
|
2651
|
+
assertNever(handleType, `Unsupported Fhevm primitive type id: ${handleType}`);
|
|
2150
2652
|
}
|
|
2151
2653
|
}
|
|
2152
2654
|
}
|
|
@@ -2171,50 +2673,38 @@ function buildDecryptionProof(kmsSignatures, extraData) {
|
|
|
2171
2673
|
]);
|
|
2172
2674
|
return decryptionProof;
|
|
2173
2675
|
}
|
|
2174
|
-
const CiphertextType = {
|
|
2175
|
-
0: 'bool',
|
|
2176
|
-
2: 'uint256',
|
|
2177
|
-
3: 'uint256',
|
|
2178
|
-
4: 'uint256',
|
|
2179
|
-
5: 'uint256',
|
|
2180
|
-
6: 'uint256',
|
|
2181
|
-
7: 'address',
|
|
2182
|
-
8: 'uint256',
|
|
2183
|
-
};
|
|
2184
2676
|
function deserializeClearValues(handles, decryptedResult) {
|
|
2185
|
-
let
|
|
2677
|
+
let fheTypeIdList = [];
|
|
2186
2678
|
for (const handle of handles) {
|
|
2187
|
-
const
|
|
2188
|
-
|
|
2189
|
-
typesList.push(typeDiscriminant);
|
|
2679
|
+
const typeDiscriminant = FhevmHandle.parse(handle).fheTypeId;
|
|
2680
|
+
fheTypeIdList.push(typeDiscriminant);
|
|
2190
2681
|
}
|
|
2191
2682
|
const restoredEncoded = '0x' +
|
|
2192
2683
|
'00'.repeat(32) + // dummy requestID (ignored)
|
|
2193
2684
|
decryptedResult.slice(2) +
|
|
2194
2685
|
'00'.repeat(32); // dummy empty bytes[] length (ignored)
|
|
2195
|
-
const abiTypes =
|
|
2196
|
-
const abiType =
|
|
2686
|
+
const abiTypes = fheTypeIdList.map((t) => {
|
|
2687
|
+
const abiType = solidityPrimitiveTypeNameFromFheTypeId(t); // all types are valid because this was supposedly checked already inside the `checkEncryptedBits` function
|
|
2197
2688
|
return abiType;
|
|
2198
2689
|
});
|
|
2199
2690
|
const coder = new ethers.AbiCoder();
|
|
2200
2691
|
const decoded = coder.decode(['uint256', ...abiTypes, 'bytes[]'], restoredEncoded);
|
|
2201
2692
|
// strip dummy first/last element
|
|
2202
|
-
const rawValues = decoded.slice(1, 1 +
|
|
2693
|
+
const rawValues = decoded.slice(1, 1 + fheTypeIdList.length);
|
|
2203
2694
|
const results = {};
|
|
2204
2695
|
handles.forEach((handle, idx) => (results[handle] = rawValues[idx]));
|
|
2205
2696
|
return results;
|
|
2206
2697
|
}
|
|
2207
|
-
const publicDecryptRequest = (kmsSigners, thresholdSigners, gatewayChainId, verifyingContractAddress, aclContractAddress,
|
|
2208
|
-
//relayerUrl: string,
|
|
2209
|
-
relayerProvider, provider, instanceOptions) => async (_handles, options) => {
|
|
2698
|
+
const publicDecryptRequest = (kmsSigners, thresholdSigners, gatewayChainId, verifyingContractAddress, aclContractAddress, relayerProvider, provider, defaultOptions) => async (_handles, options) => {
|
|
2210
2699
|
const extraData = '0x00';
|
|
2211
2700
|
const acl = new ethers.ethers.Contract(aclContractAddress, aclABI, provider);
|
|
2701
|
+
// This will be replaced by new sanitize classes
|
|
2212
2702
|
let handles;
|
|
2213
2703
|
try {
|
|
2214
2704
|
handles = await Promise.all(_handles.map(async (_handle) => {
|
|
2215
2705
|
const handle = typeof _handle === 'string'
|
|
2216
|
-
?
|
|
2217
|
-
:
|
|
2706
|
+
? bytesToHex(hexToBytes(_handle))
|
|
2707
|
+
: bytesToHex(_handle);
|
|
2218
2708
|
const isAllowedForDecryption = await acl.isAllowedForDecryption(handle);
|
|
2219
2709
|
if (!isAllowedForDecryption) {
|
|
2220
2710
|
throw new Error(`Handle ${handle} is not allowed for public decryption!`);
|
|
@@ -2231,13 +2721,10 @@ relayerProvider, provider, instanceOptions) => async (_handles, options) => {
|
|
|
2231
2721
|
ciphertextHandles: handles,
|
|
2232
2722
|
extraData,
|
|
2233
2723
|
};
|
|
2234
|
-
const json = await relayerProvider.fetchPostPublicDecrypt(payloadForRequest,
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
// payloadForRequest,
|
|
2239
|
-
// options ?? instanceOptions,
|
|
2240
|
-
// );
|
|
2724
|
+
const json = await relayerProvider.fetchPostPublicDecrypt(payloadForRequest, {
|
|
2725
|
+
...defaultOptions,
|
|
2726
|
+
...options,
|
|
2727
|
+
});
|
|
2241
2728
|
// verify signatures on decryption:
|
|
2242
2729
|
const domain = {
|
|
2243
2730
|
name: 'Decryption',
|
|
@@ -2375,8 +2862,8 @@ const createEIP712 = (verifyingContract, contractsChainId) => (publicKey, contra
|
|
|
2375
2862
|
const generateKeypair = () => {
|
|
2376
2863
|
const keypair = TKMS.ml_kem_pke_keygen();
|
|
2377
2864
|
return {
|
|
2378
|
-
publicKey:
|
|
2379
|
-
privateKey:
|
|
2865
|
+
publicKey: bytesToHexNo0x(TKMS.ml_kem_pke_pk_to_u8vec(TKMS.ml_kem_pke_get_pk(keypair))),
|
|
2866
|
+
privateKey: bytesToHexNo0x(TKMS.ml_kem_pke_sk_to_u8vec(keypair)),
|
|
2380
2867
|
};
|
|
2381
2868
|
};
|
|
2382
2869
|
|
|
@@ -2433,7 +2920,7 @@ class RelayerV1Provider extends AbstractRelayerProvider {
|
|
|
2433
2920
|
return 1;
|
|
2434
2921
|
}
|
|
2435
2922
|
async fetchGetKeyUrl() {
|
|
2436
|
-
const response = await
|
|
2923
|
+
const response = await fetchRelayerV1Get('KEY_URL', this.keyUrl);
|
|
2437
2924
|
return response;
|
|
2438
2925
|
}
|
|
2439
2926
|
async fetchPostInputProof(payload, options) {
|
|
@@ -2451,12 +2938,12 @@ class RelayerV1Provider extends AbstractRelayerProvider {
|
|
|
2451
2938
|
}
|
|
2452
2939
|
}
|
|
2453
2940
|
*/
|
|
2454
|
-
const json = await
|
|
2941
|
+
const json = await fetchRelayerV1Post('INPUT_PROOF', this.inputProof, payload, options);
|
|
2455
2942
|
assertIsRelayerInputProofResult(json.response, 'fetchPostInputProof()');
|
|
2456
2943
|
return json.response;
|
|
2457
2944
|
}
|
|
2458
2945
|
async fetchPostPublicDecrypt(payload, options) {
|
|
2459
|
-
const json = await
|
|
2946
|
+
const json = await fetchRelayerV1Post('PUBLIC_DECRYPT', this.publicDecrypt, payload, options);
|
|
2460
2947
|
const response = json.response[0];
|
|
2461
2948
|
const result = {
|
|
2462
2949
|
signatures: response.signatures,
|
|
@@ -2467,24 +2954,12 @@ class RelayerV1Provider extends AbstractRelayerProvider {
|
|
|
2467
2954
|
return result;
|
|
2468
2955
|
}
|
|
2469
2956
|
async fetchPostUserDecrypt(payload, options) {
|
|
2470
|
-
const json = await
|
|
2957
|
+
const json = await fetchRelayerV1Post('USER_DECRYPT', this.userDecrypt, payload, options);
|
|
2471
2958
|
assertIsRelayerUserDecryptResult(json.response, 'RelayerUserDecryptResult()');
|
|
2472
2959
|
return json.response;
|
|
2473
2960
|
}
|
|
2474
2961
|
}
|
|
2475
2962
|
|
|
2476
|
-
function ensureError(e) {
|
|
2477
|
-
if (e instanceof Error) {
|
|
2478
|
-
return e;
|
|
2479
|
-
}
|
|
2480
|
-
const message = e.message ?? 'Non-Error value caught in exception handler';
|
|
2481
|
-
const name = e.name ?? 'ErrorWrapper';
|
|
2482
|
-
const cause = e.cause ?? e;
|
|
2483
|
-
const err = new Error(message, { cause });
|
|
2484
|
-
err.name = name;
|
|
2485
|
-
return err;
|
|
2486
|
-
}
|
|
2487
|
-
|
|
2488
2963
|
class RelayerV2ProviderError extends RelayerErrorBase {
|
|
2489
2964
|
_operation;
|
|
2490
2965
|
constructor(params) {
|
|
@@ -2961,22 +3436,6 @@ class RelayerV2RequestInternalError extends RelayerV2RequestErrorBase {
|
|
|
2961
3436
|
}
|
|
2962
3437
|
}
|
|
2963
3438
|
|
|
2964
|
-
function assertIsRelayerV2ResultQueued(value, name) {
|
|
2965
|
-
assertRecordStringProperty(value, 'jobId', name);
|
|
2966
|
-
}
|
|
2967
|
-
|
|
2968
|
-
/*
|
|
2969
|
-
type RelayerV2ResponseQueued = {
|
|
2970
|
-
status: "queued";
|
|
2971
|
-
result: RelayerV2ResultQueued;
|
|
2972
|
-
}
|
|
2973
|
-
*/
|
|
2974
|
-
function assertIsRelayerV2ResponseQueued(value, name) {
|
|
2975
|
-
assertRecordStringProperty(value, 'status', name, 'queued');
|
|
2976
|
-
assertNonNullableRecordProperty(value, 'result', name);
|
|
2977
|
-
assertIsRelayerV2ResultQueued(value.result, `${name}.result`);
|
|
2978
|
-
}
|
|
2979
|
-
|
|
2980
3439
|
class RelayerV2ResponseApiError extends RelayerV2ResponseErrorBase {
|
|
2981
3440
|
constructor(params) {
|
|
2982
3441
|
super({
|
|
@@ -3038,7 +3497,58 @@ class RelayerV2MaxRetryError extends RelayerV2FetchErrorBase {
|
|
|
3038
3497
|
}
|
|
3039
3498
|
}
|
|
3040
3499
|
|
|
3500
|
+
function assertIsRelayerV2PostResultQueued(value, name) {
|
|
3501
|
+
assertRecordStringProperty(value, 'jobId', name);
|
|
3502
|
+
}
|
|
3503
|
+
|
|
3504
|
+
/*
|
|
3505
|
+
{
|
|
3506
|
+
status: 'queued';
|
|
3507
|
+
requestId: string;
|
|
3508
|
+
result: {
|
|
3509
|
+
jobId: string;
|
|
3510
|
+
};
|
|
3511
|
+
}
|
|
3512
|
+
*/
|
|
3513
|
+
function assertIsRelayerV2PostResponseQueued(value, name) {
|
|
3514
|
+
assertRecordStringProperty(value, 'status', name, 'queued');
|
|
3515
|
+
assertRecordStringProperty(value, 'requestId', name);
|
|
3516
|
+
assertNonNullableRecordProperty(value, 'result', name);
|
|
3517
|
+
assertIsRelayerV2PostResultQueued(value.result, `${name}.result`);
|
|
3518
|
+
}
|
|
3519
|
+
/*
|
|
3520
|
+
{
|
|
3521
|
+
status: 'queued';
|
|
3522
|
+
requestId: string;
|
|
3523
|
+
}
|
|
3524
|
+
*/
|
|
3525
|
+
function assertIsRelayerV2GetResponseQueued(value, name) {
|
|
3526
|
+
assertRecordStringProperty(value, 'status', name, 'queued');
|
|
3527
|
+
assertRecordStringProperty(value, 'requestId', name);
|
|
3528
|
+
}
|
|
3529
|
+
|
|
3530
|
+
class RelayerV2TimeoutError extends RelayerV2RequestErrorBase {
|
|
3531
|
+
constructor(params) {
|
|
3532
|
+
super({
|
|
3533
|
+
...params,
|
|
3534
|
+
name: 'RelayerV2TimeoutError',
|
|
3535
|
+
message: `Request timed out after ${params.timeoutMs}ms`,
|
|
3536
|
+
});
|
|
3537
|
+
}
|
|
3538
|
+
}
|
|
3539
|
+
|
|
3540
|
+
class RelayerV2AbortError extends RelayerV2RequestErrorBase {
|
|
3541
|
+
constructor(params) {
|
|
3542
|
+
super({
|
|
3543
|
+
...params,
|
|
3544
|
+
name: 'RelayerV2AbortError',
|
|
3545
|
+
message: `Request aborted`,
|
|
3546
|
+
});
|
|
3547
|
+
}
|
|
3548
|
+
}
|
|
3549
|
+
|
|
3041
3550
|
class RelayerV2AsyncRequest {
|
|
3551
|
+
_fetchMethod;
|
|
3042
3552
|
_jobId;
|
|
3043
3553
|
_jobIdTimestamp;
|
|
3044
3554
|
_state;
|
|
@@ -3053,17 +3563,18 @@ class RelayerV2AsyncRequest {
|
|
|
3053
3563
|
_retryAfterTimeoutID;
|
|
3054
3564
|
_url;
|
|
3055
3565
|
_payload;
|
|
3056
|
-
|
|
3566
|
+
_fhevmAuth;
|
|
3057
3567
|
_retryAfterTimeoutPromiseFuncReject;
|
|
3058
3568
|
_onProgress;
|
|
3059
|
-
|
|
3569
|
+
_requestMaxDurationInMs;
|
|
3060
3570
|
_requestStartTimestamp;
|
|
3061
3571
|
_requestGlobalTimeoutID;
|
|
3062
3572
|
_throwErrorIfNoRetryAfter;
|
|
3063
|
-
static
|
|
3064
|
-
static
|
|
3065
|
-
static
|
|
3066
|
-
static
|
|
3573
|
+
static DEFAULT_RETRY_AFTER_MS = 2500;
|
|
3574
|
+
static MINIMUM_RETRY_AFTER_MS = 1000;
|
|
3575
|
+
static DEFAULT_GLOBAL_REQUEST_TIMEOUT_MS = 60 * 60 * 1000; // 1 hour
|
|
3576
|
+
static MAX_GET_RETRY = 60 * 30; // number of default retries in 1 hour (30 retries/min)
|
|
3577
|
+
static MAX_POST_RETRY = RelayerV2AsyncRequest.MAX_GET_RETRY;
|
|
3067
3578
|
constructor(params) {
|
|
3068
3579
|
if (params.relayerOperation !== 'INPUT_PROOF' &&
|
|
3069
3580
|
params.relayerOperation !== 'PUBLIC_DECRYPT' &&
|
|
@@ -3080,14 +3591,14 @@ class RelayerV2AsyncRequest {
|
|
|
3080
3591
|
this._internalAbortController = new AbortController();
|
|
3081
3592
|
this._internalAbortSignal = this._internalAbortController.signal;
|
|
3082
3593
|
this._internalAbortSignal.addEventListener('abort', this._handleInternalSignalAbort);
|
|
3083
|
-
this._externalAbortSignal = params.signal;
|
|
3594
|
+
this._externalAbortSignal = params.options?.signal;
|
|
3084
3595
|
if (this._externalAbortSignal) {
|
|
3085
3596
|
this._externalAbortSignal.addEventListener('abort', this._handleExternalSignalAbort);
|
|
3086
3597
|
}
|
|
3087
3598
|
this._url = params.url;
|
|
3088
3599
|
this._payload = params.payload;
|
|
3089
|
-
this.
|
|
3090
|
-
this._onProgress = params.onProgress;
|
|
3600
|
+
this._fhevmAuth = params.options?.auth;
|
|
3601
|
+
this._onProgress = params.options?.onProgress;
|
|
3091
3602
|
this._state = {
|
|
3092
3603
|
aborted: false,
|
|
3093
3604
|
canceled: false,
|
|
@@ -3096,6 +3607,7 @@ class RelayerV2AsyncRequest {
|
|
|
3096
3607
|
running: false,
|
|
3097
3608
|
succeeded: false,
|
|
3098
3609
|
terminated: false,
|
|
3610
|
+
timeout: false,
|
|
3099
3611
|
};
|
|
3100
3612
|
this._retryCount = 0;
|
|
3101
3613
|
this._retryAfterTimeoutID = undefined;
|
|
@@ -3103,9 +3615,9 @@ class RelayerV2AsyncRequest {
|
|
|
3103
3615
|
this._terminateReason = undefined;
|
|
3104
3616
|
this._publicAPINoReentrancy = false;
|
|
3105
3617
|
this._throwErrorIfNoRetryAfter = params.throwErrorIfNoRetryAfter ?? false;
|
|
3106
|
-
this.
|
|
3107
|
-
params.
|
|
3108
|
-
RelayerV2AsyncRequest.
|
|
3618
|
+
this._requestMaxDurationInMs =
|
|
3619
|
+
params.options?.timeout ??
|
|
3620
|
+
RelayerV2AsyncRequest.DEFAULT_GLOBAL_REQUEST_TIMEOUT_MS;
|
|
3109
3621
|
}
|
|
3110
3622
|
//////////////////////////////////////////////////////////////////////////////
|
|
3111
3623
|
// Public API: run
|
|
@@ -3147,6 +3659,12 @@ class RelayerV2AsyncRequest {
|
|
|
3147
3659
|
state: { ...this._state },
|
|
3148
3660
|
});
|
|
3149
3661
|
}
|
|
3662
|
+
if (this._state.timeout) {
|
|
3663
|
+
throw new RelayerV2StateError({
|
|
3664
|
+
message: `Relayer.run() failed. Request already timeout.`,
|
|
3665
|
+
state: { ...this._state },
|
|
3666
|
+
});
|
|
3667
|
+
}
|
|
3150
3668
|
if (this._externalAbortSignal?.aborted === true) {
|
|
3151
3669
|
throw new RelayerV2StateError({
|
|
3152
3670
|
message: `Relayer.run() failed. External AbortSignal already aborted (reason:${this._externalAbortSignal?.reason}).`,
|
|
@@ -3167,7 +3685,7 @@ class RelayerV2AsyncRequest {
|
|
|
3167
3685
|
}
|
|
3168
3686
|
this._state.running = true;
|
|
3169
3687
|
this._requestStartTimestamp = Date.now();
|
|
3170
|
-
this._setGlobalRequestTimeout(this.
|
|
3688
|
+
this._setGlobalRequestTimeout(this._requestMaxDurationInMs);
|
|
3171
3689
|
try {
|
|
3172
3690
|
const json = await this._runPostLoop();
|
|
3173
3691
|
this._state.succeeded = true;
|
|
@@ -3238,6 +3756,12 @@ class RelayerV2AsyncRequest {
|
|
|
3238
3756
|
get failed() {
|
|
3239
3757
|
return this._state.failed;
|
|
3240
3758
|
}
|
|
3759
|
+
get aborted() {
|
|
3760
|
+
return this._state.aborted;
|
|
3761
|
+
}
|
|
3762
|
+
get timeout() {
|
|
3763
|
+
return this._state.timeout;
|
|
3764
|
+
}
|
|
3241
3765
|
get succeeded() {
|
|
3242
3766
|
return this._state.succeeded;
|
|
3243
3767
|
}
|
|
@@ -3258,6 +3782,8 @@ class RelayerV2AsyncRequest {
|
|
|
3258
3782
|
//////////////////////////////////////////////////////////////////////////////
|
|
3259
3783
|
// POST : 202 | 400 | 429 | 500 | 503
|
|
3260
3784
|
async _runPostLoop() {
|
|
3785
|
+
this._assert(this._fetchMethod === undefined, 'this._fetchMethod === undefined');
|
|
3786
|
+
this._fetchMethod = 'POST';
|
|
3261
3787
|
// No infinite loop!
|
|
3262
3788
|
let i = 0;
|
|
3263
3789
|
while (i < RelayerV2AsyncRequest.MAX_POST_RETRY) {
|
|
@@ -3282,19 +3808,18 @@ class RelayerV2AsyncRequest {
|
|
|
3282
3808
|
// - SyntaxError: Expected property name or '}' in JSON at position 1 (line 1 column 2) at JSON.parse (<anonymous>)
|
|
3283
3809
|
const bodyJson = await this._getResponseJson(response);
|
|
3284
3810
|
try {
|
|
3285
|
-
|
|
3811
|
+
assertIsRelayerV2PostResponseQueued(bodyJson, 'body');
|
|
3286
3812
|
}
|
|
3287
3813
|
catch (cause) {
|
|
3288
|
-
this.
|
|
3814
|
+
this._throwResponseInvalidBodyError({
|
|
3289
3815
|
fetchMethod: 'POST',
|
|
3290
3816
|
status: responseStatus,
|
|
3291
3817
|
cause: cause,
|
|
3292
3818
|
elapsed,
|
|
3819
|
+
bodyJson: safeJSONstringify(bodyJson),
|
|
3293
3820
|
});
|
|
3294
3821
|
}
|
|
3295
|
-
|
|
3296
|
-
if (retry_after_sec < 1)
|
|
3297
|
-
retry_after_sec = 1;
|
|
3822
|
+
const retryAfterMs = this._getRetryAfterHeaderValueInMs(response);
|
|
3298
3823
|
// Debug: will throw an assert failed error if jobId has already been set
|
|
3299
3824
|
this._setJobIdOnce(bodyJson.result.jobId);
|
|
3300
3825
|
// Async onProgress callback
|
|
@@ -3307,11 +3832,10 @@ class RelayerV2AsyncRequest {
|
|
|
3307
3832
|
jobId: this.jobId,
|
|
3308
3833
|
operation: this._relayerOperation,
|
|
3309
3834
|
retryCount: this._retryCount,
|
|
3310
|
-
|
|
3835
|
+
retryAfterMs,
|
|
3311
3836
|
elapsed,
|
|
3312
3837
|
});
|
|
3313
|
-
|
|
3314
|
-
await this._setRetryAfterTimeout(retry_after_sec * 1000);
|
|
3838
|
+
await this._setRetryAfterTimeout(retryAfterMs);
|
|
3315
3839
|
const json = await this._runGetLoop();
|
|
3316
3840
|
return json;
|
|
3317
3841
|
}
|
|
@@ -3324,11 +3848,12 @@ class RelayerV2AsyncRequest {
|
|
|
3324
3848
|
assertIsRelayerV2ResponseFailedWithError400(bodyJson, 'body');
|
|
3325
3849
|
}
|
|
3326
3850
|
catch (cause) {
|
|
3327
|
-
this.
|
|
3851
|
+
this._throwResponseInvalidBodyError({
|
|
3328
3852
|
fetchMethod: 'POST',
|
|
3329
3853
|
status: responseStatus,
|
|
3330
3854
|
cause: cause,
|
|
3331
3855
|
elapsed,
|
|
3856
|
+
bodyJson: safeJSONstringify(bodyJson),
|
|
3332
3857
|
});
|
|
3333
3858
|
}
|
|
3334
3859
|
this._throwRelayerV2ResponseApiError({
|
|
@@ -3348,29 +3873,28 @@ class RelayerV2AsyncRequest {
|
|
|
3348
3873
|
assertIsRelayerV2ResponseFailedWithError429(bodyJson, 'body');
|
|
3349
3874
|
}
|
|
3350
3875
|
catch (cause) {
|
|
3351
|
-
this.
|
|
3876
|
+
this._throwResponseInvalidBodyError({
|
|
3352
3877
|
fetchMethod: 'POST',
|
|
3353
3878
|
status: responseStatus,
|
|
3354
3879
|
cause: cause,
|
|
3355
3880
|
elapsed,
|
|
3881
|
+
bodyJson: safeJSONstringify(bodyJson),
|
|
3356
3882
|
});
|
|
3357
3883
|
}
|
|
3358
|
-
|
|
3359
|
-
if (retry_after_sec < 1)
|
|
3360
|
-
retry_after_sec = 1;
|
|
3884
|
+
const retryAfterMs = this._getRetryAfterHeaderValueInMs(response);
|
|
3361
3885
|
// Async onProgress callback
|
|
3362
3886
|
this._postAsyncOnProgressCallback({
|
|
3363
3887
|
type: 'ratelimited',
|
|
3364
3888
|
url: this._url,
|
|
3365
3889
|
method: 'POST',
|
|
3366
3890
|
status: responseStatus,
|
|
3367
|
-
|
|
3891
|
+
retryAfterMs,
|
|
3368
3892
|
retryCount: this._retryCount,
|
|
3369
3893
|
elapsed,
|
|
3370
|
-
|
|
3894
|
+
relayerApiError: bodyJson.error,
|
|
3371
3895
|
});
|
|
3372
3896
|
// Wait if needed (minimum 1s)
|
|
3373
|
-
await this._setRetryAfterTimeout(
|
|
3897
|
+
await this._setRetryAfterTimeout(retryAfterMs);
|
|
3374
3898
|
continue;
|
|
3375
3899
|
}
|
|
3376
3900
|
// RelayerV2ResponseFailed
|
|
@@ -3383,11 +3907,12 @@ class RelayerV2AsyncRequest {
|
|
|
3383
3907
|
assertIsRelayerV2ResponseFailedWithError500(bodyJson, 'body');
|
|
3384
3908
|
}
|
|
3385
3909
|
catch (cause) {
|
|
3386
|
-
this.
|
|
3910
|
+
this._throwResponseInvalidBodyError({
|
|
3387
3911
|
fetchMethod: 'POST',
|
|
3388
3912
|
status: responseStatus,
|
|
3389
3913
|
cause: cause,
|
|
3390
3914
|
elapsed,
|
|
3915
|
+
bodyJson: safeJSONstringify(bodyJson),
|
|
3391
3916
|
});
|
|
3392
3917
|
}
|
|
3393
3918
|
this._throwRelayerV2ResponseApiError({
|
|
@@ -3407,11 +3932,12 @@ class RelayerV2AsyncRequest {
|
|
|
3407
3932
|
assertIsRelayerV2ResponseFailedWithError503(bodyJson, 'body');
|
|
3408
3933
|
}
|
|
3409
3934
|
catch (cause) {
|
|
3410
|
-
this.
|
|
3935
|
+
this._throwResponseInvalidBodyError({
|
|
3411
3936
|
fetchMethod: 'POST',
|
|
3412
3937
|
status: responseStatus,
|
|
3413
3938
|
cause: cause,
|
|
3414
3939
|
elapsed,
|
|
3940
|
+
bodyJson: safeJSONstringify(bodyJson),
|
|
3415
3941
|
});
|
|
3416
3942
|
}
|
|
3417
3943
|
this._throwRelayerV2ResponseApiError({
|
|
@@ -3447,8 +3973,10 @@ class RelayerV2AsyncRequest {
|
|
|
3447
3973
|
// GET: 200 | 202 | 404 | 500 | 503 | 504
|
|
3448
3974
|
// GET is not rate-limited, therefore there is not 429 error
|
|
3449
3975
|
async _runGetLoop() {
|
|
3976
|
+
this._assert(this._fetchMethod === 'POST', "this._fetchMethod === 'POST'");
|
|
3450
3977
|
this._assert(this._jobId !== undefined, 'this._jobId !== undefined');
|
|
3451
3978
|
this._assert(this._jobIdTimestamp !== undefined, 'this._jobIdTimestamp !== undefined');
|
|
3979
|
+
this._fetchMethod = 'GET';
|
|
3452
3980
|
let i = 0;
|
|
3453
3981
|
while (i < RelayerV2AsyncRequest.MAX_GET_RETRY) {
|
|
3454
3982
|
++i;
|
|
@@ -3535,6 +4063,7 @@ class RelayerV2AsyncRequest {
|
|
|
3535
4063
|
status: responseStatus,
|
|
3536
4064
|
elapsed,
|
|
3537
4065
|
cause: cause,
|
|
4066
|
+
bodyJson: safeJSONstringify(bodyJson),
|
|
3538
4067
|
});
|
|
3539
4068
|
}
|
|
3540
4069
|
// RelayerV2ResultPublicDecrypt
|
|
@@ -3546,7 +4075,7 @@ class RelayerV2AsyncRequest {
|
|
|
3546
4075
|
case 202: {
|
|
3547
4076
|
const bodyJson = await this._getResponseJson(response);
|
|
3548
4077
|
try {
|
|
3549
|
-
|
|
4078
|
+
assertIsRelayerV2GetResponseQueued(bodyJson, 'body');
|
|
3550
4079
|
}
|
|
3551
4080
|
catch (cause) {
|
|
3552
4081
|
this._throwResponseInvalidBodyError({
|
|
@@ -3554,11 +4083,10 @@ class RelayerV2AsyncRequest {
|
|
|
3554
4083
|
status: responseStatus,
|
|
3555
4084
|
elapsed,
|
|
3556
4085
|
cause: cause,
|
|
4086
|
+
bodyJson: safeJSONstringify(bodyJson),
|
|
3557
4087
|
});
|
|
3558
4088
|
}
|
|
3559
|
-
|
|
3560
|
-
if (retry_after_sec < 1)
|
|
3561
|
-
retry_after_sec = 1;
|
|
4089
|
+
const retryAfterMs = this._getRetryAfterHeaderValueInMs(response);
|
|
3562
4090
|
// Async onProgress callback
|
|
3563
4091
|
this._postAsyncOnProgressCallback({
|
|
3564
4092
|
type: 'queued',
|
|
@@ -3568,12 +4096,12 @@ class RelayerV2AsyncRequest {
|
|
|
3568
4096
|
requestId: bodyJson.requestId,
|
|
3569
4097
|
operation: this._relayerOperation,
|
|
3570
4098
|
jobId: this.jobId,
|
|
3571
|
-
|
|
4099
|
+
retryAfterMs,
|
|
3572
4100
|
retryCount: this._retryCount,
|
|
3573
4101
|
elapsed,
|
|
3574
4102
|
});
|
|
3575
4103
|
// Wait if needed (minimum 1s)
|
|
3576
|
-
await this._setRetryAfterTimeout(
|
|
4104
|
+
await this._setRetryAfterTimeout(retryAfterMs);
|
|
3577
4105
|
continue;
|
|
3578
4106
|
}
|
|
3579
4107
|
case 400: {
|
|
@@ -3589,6 +4117,7 @@ class RelayerV2AsyncRequest {
|
|
|
3589
4117
|
status: responseStatus,
|
|
3590
4118
|
elapsed,
|
|
3591
4119
|
cause: cause,
|
|
4120
|
+
bodyJson: safeJSONstringify(bodyJson),
|
|
3592
4121
|
});
|
|
3593
4122
|
}
|
|
3594
4123
|
this._throwRelayerV2ResponseApiError({
|
|
@@ -3611,6 +4140,7 @@ class RelayerV2AsyncRequest {
|
|
|
3611
4140
|
status: responseStatus,
|
|
3612
4141
|
elapsed,
|
|
3613
4142
|
cause: cause,
|
|
4143
|
+
bodyJson: safeJSONstringify(bodyJson),
|
|
3614
4144
|
});
|
|
3615
4145
|
}
|
|
3616
4146
|
this._throwRelayerV2ResponseApiError({
|
|
@@ -3635,6 +4165,7 @@ class RelayerV2AsyncRequest {
|
|
|
3635
4165
|
status: responseStatus,
|
|
3636
4166
|
elapsed,
|
|
3637
4167
|
cause: cause,
|
|
4168
|
+
bodyJson: safeJSONstringify(bodyJson),
|
|
3638
4169
|
});
|
|
3639
4170
|
}
|
|
3640
4171
|
this._throwRelayerV2ResponseApiError({
|
|
@@ -3659,6 +4190,7 @@ class RelayerV2AsyncRequest {
|
|
|
3659
4190
|
status: responseStatus,
|
|
3660
4191
|
elapsed,
|
|
3661
4192
|
cause: cause,
|
|
4193
|
+
bodyJson: safeJSONstringify(bodyJson),
|
|
3662
4194
|
});
|
|
3663
4195
|
}
|
|
3664
4196
|
this._throwRelayerV2ResponseApiError({
|
|
@@ -3683,6 +4215,7 @@ class RelayerV2AsyncRequest {
|
|
|
3683
4215
|
status: responseStatus,
|
|
3684
4216
|
elapsed,
|
|
3685
4217
|
cause: cause,
|
|
4218
|
+
bodyJson: safeJSONstringify(bodyJson),
|
|
3686
4219
|
});
|
|
3687
4220
|
}
|
|
3688
4221
|
this._throwRelayerV2ResponseApiError({
|
|
@@ -3720,17 +4253,20 @@ class RelayerV2AsyncRequest {
|
|
|
3720
4253
|
return bodyJson;
|
|
3721
4254
|
}
|
|
3722
4255
|
//////////////////////////////////////////////////////////////////////////////
|
|
3723
|
-
|
|
4256
|
+
_getRetryAfterHeaderValueInMs(response) {
|
|
3724
4257
|
if (!response.headers.has('Retry-After')) {
|
|
3725
4258
|
if (this._throwErrorIfNoRetryAfter) {
|
|
3726
4259
|
throw new Error(`Missing 'Retry-After' header key`);
|
|
3727
4260
|
}
|
|
3728
|
-
return RelayerV2AsyncRequest.
|
|
4261
|
+
return RelayerV2AsyncRequest.DEFAULT_RETRY_AFTER_MS;
|
|
3729
4262
|
}
|
|
3730
4263
|
try {
|
|
3731
4264
|
const n = Number.parseInt(response.headers.get('Retry-After'));
|
|
3732
4265
|
if (isUint(n)) {
|
|
3733
|
-
|
|
4266
|
+
const ms = n * 1000;
|
|
4267
|
+
return ms < RelayerV2AsyncRequest.MINIMUM_RETRY_AFTER_MS
|
|
4268
|
+
? RelayerV2AsyncRequest.MINIMUM_RETRY_AFTER_MS
|
|
4269
|
+
: ms;
|
|
3734
4270
|
}
|
|
3735
4271
|
}
|
|
3736
4272
|
catch {
|
|
@@ -3739,7 +4275,7 @@ class RelayerV2AsyncRequest {
|
|
|
3739
4275
|
if (this._throwErrorIfNoRetryAfter) {
|
|
3740
4276
|
throw new Error(`Invalid 'Retry-After' header key`);
|
|
3741
4277
|
}
|
|
3742
|
-
return RelayerV2AsyncRequest.
|
|
4278
|
+
return RelayerV2AsyncRequest.DEFAULT_RETRY_AFTER_MS;
|
|
3743
4279
|
}
|
|
3744
4280
|
//////////////////////////////////////////////////////////////////////////////
|
|
3745
4281
|
// JobId
|
|
@@ -3778,17 +4314,19 @@ class RelayerV2AsyncRequest {
|
|
|
3778
4314
|
this._assert(this._jobId === undefined, 'this._jobId === undefined');
|
|
3779
4315
|
this._assert(!this._state.terminated, '!this._state.terminated');
|
|
3780
4316
|
this._assert(!this._state.fetching, '!this._state.fetching');
|
|
3781
|
-
this._trace('_fetchPost',
|
|
4317
|
+
this._trace('_fetchPost', this._url);
|
|
3782
4318
|
const init = setAuth({
|
|
3783
4319
|
method: 'POST',
|
|
3784
4320
|
headers: {
|
|
3785
4321
|
'Content-Type': 'application/json',
|
|
4322
|
+
'ZAMA-SDK-VERSION': `${version}`,
|
|
4323
|
+
'ZAMA-SDK-NAME': `${sdkName}`,
|
|
3786
4324
|
},
|
|
3787
4325
|
body: JSON.stringify(this._payload),
|
|
3788
4326
|
...(this._internalAbortSignal
|
|
3789
4327
|
? { signal: this._internalAbortSignal }
|
|
3790
4328
|
: {}),
|
|
3791
|
-
}, this.
|
|
4329
|
+
}, this._fhevmAuth);
|
|
3792
4330
|
this._state.fetching = true;
|
|
3793
4331
|
let response;
|
|
3794
4332
|
try {
|
|
@@ -3832,9 +4370,16 @@ class RelayerV2AsyncRequest {
|
|
|
3832
4370
|
this._assert(!this._state.terminated, '!this._state.terminated');
|
|
3833
4371
|
this._assert(!this._state.fetching, '!this._state.fetching');
|
|
3834
4372
|
this._trace('_fetchGet', `jobId=${this.jobId}`);
|
|
3835
|
-
const init =
|
|
3836
|
-
|
|
3837
|
-
:
|
|
4373
|
+
const init = {
|
|
4374
|
+
method: 'GET',
|
|
4375
|
+
headers: {
|
|
4376
|
+
'ZAMA-SDK-VERSION': `${version}`,
|
|
4377
|
+
'ZAMA-SDK-NAME': `${sdkName}`,
|
|
4378
|
+
},
|
|
4379
|
+
...(this._internalAbortSignal
|
|
4380
|
+
? { signal: this._internalAbortSignal }
|
|
4381
|
+
: {}),
|
|
4382
|
+
};
|
|
3838
4383
|
this._state.fetching = true;
|
|
3839
4384
|
let response;
|
|
3840
4385
|
try {
|
|
@@ -3908,7 +4453,18 @@ class RelayerV2AsyncRequest {
|
|
|
3908
4453
|
if (signal.reason !== 'cancel') {
|
|
3909
4454
|
this._assert(!this._state.canceled, '!this._state.canceled');
|
|
3910
4455
|
}
|
|
3911
|
-
this.
|
|
4456
|
+
this._postAsyncOnProgressCallback({
|
|
4457
|
+
type: 'abort',
|
|
4458
|
+
url: this._url,
|
|
4459
|
+
...(this._jobId ? { jobId: this._jobId } : {}),
|
|
4460
|
+
operation: this._relayerOperation,
|
|
4461
|
+
retryCount: this._retryCount,
|
|
4462
|
+
});
|
|
4463
|
+
this._terminate('abort', new RelayerV2AbortError({
|
|
4464
|
+
operation: this._relayerOperation,
|
|
4465
|
+
jobId: this._jobId,
|
|
4466
|
+
url: this._url,
|
|
4467
|
+
}));
|
|
3912
4468
|
};
|
|
3913
4469
|
//////////////////////////////////////////////////////////////////////////////
|
|
3914
4470
|
// Terminate
|
|
@@ -3932,7 +4488,7 @@ class RelayerV2AsyncRequest {
|
|
|
3932
4488
|
this._terminateReason = reason;
|
|
3933
4489
|
this._terminateError = error;
|
|
3934
4490
|
this._state.terminated = true;
|
|
3935
|
-
this._tryClearRetryAfterTimeout();
|
|
4491
|
+
this._tryClearRetryAfterTimeout(error);
|
|
3936
4492
|
this._tryClearGlobalRequestTimeout();
|
|
3937
4493
|
const is = this._internalAbortSignal;
|
|
3938
4494
|
const es = this._externalAbortSignal;
|
|
@@ -3954,7 +4510,7 @@ class RelayerV2AsyncRequest {
|
|
|
3954
4510
|
// Debug
|
|
3955
4511
|
this._assert(!this._state.terminated, '!this._state.terminated');
|
|
3956
4512
|
this._assert(this._retryAfterTimeoutID === undefined, 'this._retryAfterTimeoutID === undefined');
|
|
3957
|
-
this._assert(delayMs >=
|
|
4513
|
+
this._assert(delayMs >= RelayerV2AsyncRequest.MINIMUM_RETRY_AFTER_MS, `delayMs >= ${RelayerV2AsyncRequest.MINIMUM_RETRY_AFTER_MS}`);
|
|
3958
4514
|
this._trace('_setRetryAfterTimeout', `delayMs=${delayMs}`);
|
|
3959
4515
|
if (this._retryAfterTimeoutID !== undefined) {
|
|
3960
4516
|
return Promise.reject(new Error(`retry-after already running.`));
|
|
@@ -3974,7 +4530,7 @@ class RelayerV2AsyncRequest {
|
|
|
3974
4530
|
return p;
|
|
3975
4531
|
}
|
|
3976
4532
|
//////////////////////////////////////////////////////////////////////////////
|
|
3977
|
-
_tryClearRetryAfterTimeout() {
|
|
4533
|
+
_tryClearRetryAfterTimeout(error) {
|
|
3978
4534
|
if (this._retryAfterTimeoutID === undefined) {
|
|
3979
4535
|
// Debug
|
|
3980
4536
|
this._assert(this._retryAfterTimeoutPromiseFuncReject === undefined, 'this._retryAfterTimeoutPromiseFuncReject === undefined');
|
|
@@ -3985,7 +4541,8 @@ class RelayerV2AsyncRequest {
|
|
|
3985
4541
|
this._retryAfterTimeoutID = undefined;
|
|
3986
4542
|
this._retryAfterTimeoutPromiseFuncReject = undefined;
|
|
3987
4543
|
clearTimeout(tid);
|
|
3988
|
-
reject
|
|
4544
|
+
// Calling reject will
|
|
4545
|
+
reject(error ?? new Error('_tryClearRetryAfterTimeout'));
|
|
3989
4546
|
}
|
|
3990
4547
|
//////////////////////////////////////////////////////////////////////////////
|
|
3991
4548
|
// Global Request Timeout
|
|
@@ -4000,7 +4557,24 @@ class RelayerV2AsyncRequest {
|
|
|
4000
4557
|
this._requestGlobalTimeoutID = setTimeout(callback, delayMs);
|
|
4001
4558
|
}
|
|
4002
4559
|
_handleGlobalRequestTimeout() {
|
|
4003
|
-
this.
|
|
4560
|
+
this._state.timeout = true;
|
|
4561
|
+
// Debug state-check guards:
|
|
4562
|
+
this._assert(this instanceof RelayerV2AsyncRequest, `this instanceof RelayerV2AsyncRequest`);
|
|
4563
|
+
this._assert(!this._state.terminated, `!this._state.terminated`);
|
|
4564
|
+
this._assert(!this._state.timeout, '!this._state.timeout');
|
|
4565
|
+
this._postAsyncOnProgressCallback({
|
|
4566
|
+
type: 'timeout',
|
|
4567
|
+
url: this._url,
|
|
4568
|
+
...(this._jobId ? { jobId: this._jobId } : {}),
|
|
4569
|
+
operation: this._relayerOperation,
|
|
4570
|
+
retryCount: this._retryCount,
|
|
4571
|
+
});
|
|
4572
|
+
this._terminate('timeout', new RelayerV2TimeoutError({
|
|
4573
|
+
operation: this._relayerOperation,
|
|
4574
|
+
jobId: this._jobId,
|
|
4575
|
+
url: this._url,
|
|
4576
|
+
timeoutMs: this._requestMaxDurationInMs,
|
|
4577
|
+
}));
|
|
4004
4578
|
}
|
|
4005
4579
|
_tryClearGlobalRequestTimeout() {
|
|
4006
4580
|
if (this._requestGlobalTimeoutID === undefined) {
|
|
@@ -4087,20 +4661,11 @@ class RelayerV2AsyncRequest {
|
|
|
4087
4661
|
elapsed,
|
|
4088
4662
|
});
|
|
4089
4663
|
}
|
|
4090
|
-
_throwInvalidResponseError(params) {
|
|
4091
|
-
throw new RelayerV2ResponseInvalidBodyError({
|
|
4092
|
-
...params,
|
|
4093
|
-
url: this._url,
|
|
4094
|
-
operation: this._relayerOperation,
|
|
4095
|
-
state: { ...this._state },
|
|
4096
|
-
retryCount: this._retryCount,
|
|
4097
|
-
});
|
|
4098
|
-
}
|
|
4099
4664
|
_throwResponseInvalidBodyError(params) {
|
|
4100
4665
|
throw new RelayerV2ResponseInvalidBodyError({
|
|
4101
4666
|
...params,
|
|
4102
4667
|
url: this._url,
|
|
4103
|
-
jobId: this.
|
|
4668
|
+
jobId: this._jobId,
|
|
4104
4669
|
operation: this._relayerOperation,
|
|
4105
4670
|
state: { ...this._state },
|
|
4106
4671
|
retryCount: this._retryCount,
|
|
@@ -4171,7 +4736,7 @@ function assertIsRelayerV2KeyData(value, name) {
|
|
|
4171
4736
|
assertRecordStringProperty(value, 'dataId', name);
|
|
4172
4737
|
assertRecordStringArrayProperty(value, 'urls', name);
|
|
4173
4738
|
}
|
|
4174
|
-
function
|
|
4739
|
+
function toRelayerV1KeyUrlResponse(response) {
|
|
4175
4740
|
const fheKeyInfoV1 = response.response.fheKeyInfo.map((v2Info) => ({
|
|
4176
4741
|
fhe_public_key: {
|
|
4177
4742
|
data_id: v2Info.fhePublicKey.dataId,
|
|
@@ -4201,7 +4766,7 @@ class RelayerV2Provider extends AbstractRelayerProvider {
|
|
|
4201
4766
|
return 2;
|
|
4202
4767
|
}
|
|
4203
4768
|
async fetchGetKeyUrlV2() {
|
|
4204
|
-
const response = await
|
|
4769
|
+
const response = await fetchRelayerV1Get('KEY_URL', this.keyUrl);
|
|
4205
4770
|
// Relayer error
|
|
4206
4771
|
try {
|
|
4207
4772
|
assertIsRelayerV2GetResponseKeyUrl(response, 'fetchGetKeyUrl()');
|
|
@@ -4215,39 +4780,36 @@ class RelayerV2Provider extends AbstractRelayerProvider {
|
|
|
4215
4780
|
}
|
|
4216
4781
|
async fetchGetKeyUrl() {
|
|
4217
4782
|
const response = await this.fetchGetKeyUrlV2();
|
|
4218
|
-
return
|
|
4783
|
+
return toRelayerV1KeyUrlResponse(response);
|
|
4219
4784
|
}
|
|
4220
|
-
async fetchPostInputProof(payload,
|
|
4785
|
+
async fetchPostInputProof(payload, options) {
|
|
4221
4786
|
const request = new RelayerV2AsyncRequest({
|
|
4222
4787
|
relayerOperation: 'INPUT_PROOF',
|
|
4223
4788
|
url: this.inputProof,
|
|
4224
4789
|
payload,
|
|
4225
|
-
|
|
4226
|
-
...fetchOptions,
|
|
4790
|
+
options,
|
|
4227
4791
|
});
|
|
4228
4792
|
const result = (await request.run());
|
|
4229
4793
|
assertIsRelayerInputProofResult(result, 'fetchPostInputProof()');
|
|
4230
4794
|
return result;
|
|
4231
4795
|
}
|
|
4232
|
-
async fetchPostPublicDecrypt(payload,
|
|
4796
|
+
async fetchPostPublicDecrypt(payload, options) {
|
|
4233
4797
|
const request = new RelayerV2AsyncRequest({
|
|
4234
4798
|
relayerOperation: 'PUBLIC_DECRYPT',
|
|
4235
4799
|
url: this.publicDecrypt,
|
|
4236
4800
|
payload,
|
|
4237
|
-
|
|
4238
|
-
...fetchOptions,
|
|
4801
|
+
options,
|
|
4239
4802
|
});
|
|
4240
4803
|
const result = await request.run();
|
|
4241
4804
|
assertIsRelayerPublicDecryptResult(result, 'fetchPostPublicDecrypt()');
|
|
4242
4805
|
return result;
|
|
4243
4806
|
}
|
|
4244
|
-
async fetchPostUserDecrypt(payload,
|
|
4807
|
+
async fetchPostUserDecrypt(payload, options) {
|
|
4245
4808
|
const request = new RelayerV2AsyncRequest({
|
|
4246
4809
|
relayerOperation: 'USER_DECRYPT',
|
|
4247
4810
|
url: this.userDecrypt,
|
|
4248
4811
|
payload,
|
|
4249
|
-
|
|
4250
|
-
...fetchOptions,
|
|
4812
|
+
options,
|
|
4251
4813
|
});
|
|
4252
4814
|
const result = (await request.run());
|
|
4253
4815
|
assertIsRelayerUserDecryptResult(result.result, 'fetchPostUserDecrypt()');
|
|
@@ -4255,6 +4817,16 @@ class RelayerV2Provider extends AbstractRelayerProvider {
|
|
|
4255
4817
|
}
|
|
4256
4818
|
}
|
|
4257
4819
|
|
|
4820
|
+
class TFHECrsError extends RelayerErrorBase {
|
|
4821
|
+
constructor({ message, cause }) {
|
|
4822
|
+
super({
|
|
4823
|
+
message,
|
|
4824
|
+
name: 'TFHECrsError',
|
|
4825
|
+
...(cause ? { cause: ensureError(cause) } : {}),
|
|
4826
|
+
});
|
|
4827
|
+
}
|
|
4828
|
+
}
|
|
4829
|
+
|
|
4258
4830
|
class AbstractRelayerFhevm {
|
|
4259
4831
|
}
|
|
4260
4832
|
|
|
@@ -4269,6 +4841,15 @@ class TFHECrs {
|
|
|
4269
4841
|
this._bits = params.bits;
|
|
4270
4842
|
this._srcUrl = params.srcUrl;
|
|
4271
4843
|
}
|
|
4844
|
+
get id() {
|
|
4845
|
+
return this._id;
|
|
4846
|
+
}
|
|
4847
|
+
get bits() {
|
|
4848
|
+
return this._bits;
|
|
4849
|
+
}
|
|
4850
|
+
get srcUrl() {
|
|
4851
|
+
return this._srcUrl;
|
|
4852
|
+
}
|
|
4272
4853
|
/*
|
|
4273
4854
|
{
|
|
4274
4855
|
id: string,
|
|
@@ -4371,20 +4952,58 @@ class TFHECrs {
|
|
|
4371
4952
|
return TFHECrs._fromUrl(params);
|
|
4372
4953
|
}
|
|
4373
4954
|
else {
|
|
4374
|
-
throw new
|
|
4955
|
+
throw new TFHECrsError({
|
|
4956
|
+
message: 'Invalid public key (deserialization failed)',
|
|
4957
|
+
});
|
|
4375
4958
|
}
|
|
4376
4959
|
}
|
|
4960
|
+
/*
|
|
4961
|
+
{
|
|
4962
|
+
id: string;
|
|
4963
|
+
data: Uint8Array;
|
|
4964
|
+
bits: number;
|
|
4965
|
+
srcUrl?: string;
|
|
4966
|
+
}
|
|
4967
|
+
*/
|
|
4377
4968
|
static fromBytes(params) {
|
|
4378
4969
|
try {
|
|
4379
4970
|
TFHECrs.assertKeyBytesType(params, 'arg');
|
|
4380
4971
|
return TFHECrs._fromBytes(params);
|
|
4381
4972
|
}
|
|
4382
4973
|
catch (e) {
|
|
4383
|
-
throw new
|
|
4974
|
+
throw new TFHECrsError({
|
|
4975
|
+
message: 'Invalid public key (deserialization failed)',
|
|
4384
4976
|
cause: e,
|
|
4385
4977
|
});
|
|
4386
4978
|
}
|
|
4387
4979
|
}
|
|
4980
|
+
/*
|
|
4981
|
+
{
|
|
4982
|
+
id: string;
|
|
4983
|
+
data: BytesHex;
|
|
4984
|
+
bits: number;
|
|
4985
|
+
srcUrl?: string;
|
|
4986
|
+
}
|
|
4987
|
+
*/
|
|
4988
|
+
static fromBytesHex(params) {
|
|
4989
|
+
let data;
|
|
4990
|
+
try {
|
|
4991
|
+
assertRecordStringProperty(params, 'data', 'arg');
|
|
4992
|
+
data = hexToBytesFaster(params.data, true /* strict */);
|
|
4993
|
+
}
|
|
4994
|
+
catch (e) {
|
|
4995
|
+
throw new TFHECrsError({
|
|
4996
|
+
message: 'Invalid public key (deserialization failed)',
|
|
4997
|
+
cause: e,
|
|
4998
|
+
});
|
|
4999
|
+
}
|
|
5000
|
+
return TFHECrs.fromBytes({
|
|
5001
|
+
id: params?.id,
|
|
5002
|
+
bits: params?.bits,
|
|
5003
|
+
srcUrl: params?.srcUrl,
|
|
5004
|
+
data,
|
|
5005
|
+
});
|
|
5006
|
+
}
|
|
4388
5007
|
static _fromBytes(params) {
|
|
4389
5008
|
const _params = {
|
|
4390
5009
|
compactPkeCrs: TFHE.CompactPkeCrs.safe_deserialize(params.data, SERIALIZED_SIZE_LIMIT_CRS),
|
|
@@ -4400,7 +5019,50 @@ class TFHECrs {
|
|
|
4400
5019
|
return TFHECrs._fromPublicParamsBytes(params);
|
|
4401
5020
|
}
|
|
4402
5021
|
catch (e) {
|
|
4403
|
-
throw new
|
|
5022
|
+
throw new TFHECrsError({
|
|
5023
|
+
message: 'Invalid public key (deserialization failed)',
|
|
5024
|
+
cause: e,
|
|
5025
|
+
});
|
|
5026
|
+
}
|
|
5027
|
+
}
|
|
5028
|
+
static fromBitsPublicParamsBytes(bits, params) {
|
|
5029
|
+
if (bits === undefined) {
|
|
5030
|
+
throw new TFHECrsError({ message: 'Missing PublicParams bits format' });
|
|
5031
|
+
}
|
|
5032
|
+
if (bits !== 2048) {
|
|
5033
|
+
throw new TFHECrsError({
|
|
5034
|
+
message: `Unsupported PublicParams bits format '${bits}'`,
|
|
5035
|
+
});
|
|
5036
|
+
}
|
|
5037
|
+
try {
|
|
5038
|
+
assertRecordStringProperty(params, 'publicParamsId', `arg`);
|
|
5039
|
+
assertUint8ArrayProperty(params, 'publicParams', `arg`);
|
|
5040
|
+
return TFHECrs._fromPublicParamsBytes({
|
|
5041
|
+
2048: params,
|
|
5042
|
+
});
|
|
5043
|
+
}
|
|
5044
|
+
catch (e) {
|
|
5045
|
+
throw new TFHECrsError({
|
|
5046
|
+
message: 'Invalid public key (deserialization failed)',
|
|
5047
|
+
cause: e,
|
|
5048
|
+
});
|
|
5049
|
+
}
|
|
5050
|
+
}
|
|
5051
|
+
static fromPublicParamsBytesHex(params) {
|
|
5052
|
+
try {
|
|
5053
|
+
assertNonNullableRecordProperty(params, '2048', 'arg');
|
|
5054
|
+
assertRecordStringProperty(params['2048'], 'publicParamsId', `arg.2048`);
|
|
5055
|
+
assertRecordStringProperty(params['2048'], 'publicParams', `arg.2048`);
|
|
5056
|
+
return TFHECrs._fromPublicParamsBytes({
|
|
5057
|
+
2048: {
|
|
5058
|
+
publicParams: hexToBytesFaster(params['2048'].publicParams, true /* strict */),
|
|
5059
|
+
publicParamsId: params['2048'].publicParamsId,
|
|
5060
|
+
},
|
|
5061
|
+
});
|
|
5062
|
+
}
|
|
5063
|
+
catch (e) {
|
|
5064
|
+
throw new TFHECrsError({
|
|
5065
|
+
message: 'Invalid public key (deserialization failed)',
|
|
4404
5066
|
cause: e,
|
|
4405
5067
|
});
|
|
4406
5068
|
}
|
|
@@ -4418,7 +5080,8 @@ class TFHECrs {
|
|
|
4418
5080
|
return TFHECrs._fromUrl(params);
|
|
4419
5081
|
}
|
|
4420
5082
|
catch (e) {
|
|
4421
|
-
throw new
|
|
5083
|
+
throw new TFHECrsError({
|
|
5084
|
+
message: 'Impossible to fetch public key: wrong relayer url.',
|
|
4422
5085
|
cause: e,
|
|
4423
5086
|
});
|
|
4424
5087
|
}
|
|
@@ -4449,6 +5112,22 @@ class TFHECrs {
|
|
|
4449
5112
|
...(this._srcUrl ? { srcUrl: this._srcUrl } : {}),
|
|
4450
5113
|
};
|
|
4451
5114
|
}
|
|
5115
|
+
/*
|
|
5116
|
+
{
|
|
5117
|
+
id: string,
|
|
5118
|
+
bits: number,
|
|
5119
|
+
data: BytesHex,
|
|
5120
|
+
srcUrl?: string
|
|
5121
|
+
}
|
|
5122
|
+
*/
|
|
5123
|
+
toBytesHex() {
|
|
5124
|
+
return {
|
|
5125
|
+
data: bytesToHexLarge(this._compactPkeCrs.safe_serialize(SERIALIZED_SIZE_LIMIT_CRS)),
|
|
5126
|
+
id: this._id,
|
|
5127
|
+
bits: this._bits,
|
|
5128
|
+
...(this._srcUrl ? { srcUrl: this._srcUrl } : {}),
|
|
5129
|
+
};
|
|
5130
|
+
}
|
|
4452
5131
|
/*
|
|
4453
5132
|
{
|
|
4454
5133
|
2048: {
|
|
@@ -4457,9 +5136,11 @@ class TFHECrs {
|
|
|
4457
5136
|
}
|
|
4458
5137
|
}
|
|
4459
5138
|
*/
|
|
4460
|
-
|
|
5139
|
+
toPublicParams2048Wasm() {
|
|
4461
5140
|
if (this._bits !== 2048) {
|
|
4462
|
-
throw new
|
|
5141
|
+
throw new TFHECrsError({
|
|
5142
|
+
message: `Unsupported PublicParams bits format '2048'`,
|
|
5143
|
+
});
|
|
4463
5144
|
}
|
|
4464
5145
|
const pp = {
|
|
4465
5146
|
2048: {
|
|
@@ -4477,9 +5158,11 @@ class TFHECrs {
|
|
|
4477
5158
|
}
|
|
4478
5159
|
}
|
|
4479
5160
|
*/
|
|
4480
|
-
|
|
5161
|
+
toPublicParams2048Bytes() {
|
|
4481
5162
|
if (this._bits !== 2048) {
|
|
4482
|
-
throw new
|
|
5163
|
+
throw new TFHECrsError({
|
|
5164
|
+
message: `Unsupported PublicParams bits format '2048'`,
|
|
5165
|
+
});
|
|
4483
5166
|
}
|
|
4484
5167
|
const pp = {
|
|
4485
5168
|
2048: {
|
|
@@ -4489,6 +5172,64 @@ class TFHECrs {
|
|
|
4489
5172
|
};
|
|
4490
5173
|
return pp;
|
|
4491
5174
|
}
|
|
5175
|
+
/*
|
|
5176
|
+
{
|
|
5177
|
+
2048: {
|
|
5178
|
+
publicParamsId: string,
|
|
5179
|
+
publicParams: BytesHex
|
|
5180
|
+
}
|
|
5181
|
+
}
|
|
5182
|
+
*/
|
|
5183
|
+
toPublicParams2048BytesHex() {
|
|
5184
|
+
if (this._bits === undefined) {
|
|
5185
|
+
throw new TFHECrsError({ message: 'Missing PublicParams bits format' });
|
|
5186
|
+
}
|
|
5187
|
+
if (this._bits !== 2048) {
|
|
5188
|
+
throw new TFHECrsError({
|
|
5189
|
+
message: `Unsupported PublicParams bits format '${this._bits}'`,
|
|
5190
|
+
});
|
|
5191
|
+
}
|
|
5192
|
+
const pp = {
|
|
5193
|
+
2048: {
|
|
5194
|
+
publicParams: this.toBytesHex().data,
|
|
5195
|
+
publicParamsId: this._id,
|
|
5196
|
+
},
|
|
5197
|
+
};
|
|
5198
|
+
return pp;
|
|
5199
|
+
}
|
|
5200
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
5201
|
+
// JSON
|
|
5202
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
5203
|
+
/*
|
|
5204
|
+
{
|
|
5205
|
+
__type: 'TFHECrs',
|
|
5206
|
+
id: string,
|
|
5207
|
+
data: BytesHex,
|
|
5208
|
+
srcUrl?: string
|
|
5209
|
+
}
|
|
5210
|
+
*/
|
|
5211
|
+
toJSON() {
|
|
5212
|
+
return {
|
|
5213
|
+
__type: 'TFHECrs',
|
|
5214
|
+
...this.toBytesHex(),
|
|
5215
|
+
};
|
|
5216
|
+
}
|
|
5217
|
+
static fromJSON(json) {
|
|
5218
|
+
if (json.__type !== 'TFHECrs') {
|
|
5219
|
+
throw new TFHECrsError({ message: 'Invalid TFHECrs JSON.' });
|
|
5220
|
+
}
|
|
5221
|
+
return TFHECrs.fromBytesHex(json);
|
|
5222
|
+
}
|
|
5223
|
+
}
|
|
5224
|
+
|
|
5225
|
+
class TFHEPublicKeyError extends RelayerErrorBase {
|
|
5226
|
+
constructor({ message, cause }) {
|
|
5227
|
+
super({
|
|
5228
|
+
message,
|
|
5229
|
+
name: 'TFHEPublicKeyError',
|
|
5230
|
+
...(cause ? { cause: ensureError(cause) } : {}),
|
|
5231
|
+
});
|
|
5232
|
+
}
|
|
4492
5233
|
}
|
|
4493
5234
|
|
|
4494
5235
|
class TFHEPublicKey {
|
|
@@ -4500,6 +5241,12 @@ class TFHEPublicKey {
|
|
|
4500
5241
|
this._tfheCompactPublicKey = params.tfheCompactPublicKey;
|
|
4501
5242
|
this._srcUrl = params.srcUrl;
|
|
4502
5243
|
}
|
|
5244
|
+
get id() {
|
|
5245
|
+
return this._id;
|
|
5246
|
+
}
|
|
5247
|
+
get srcUrl() {
|
|
5248
|
+
return this._srcUrl;
|
|
5249
|
+
}
|
|
4503
5250
|
/*
|
|
4504
5251
|
{
|
|
4505
5252
|
id: string,
|
|
@@ -4584,6 +5331,30 @@ class TFHEPublicKey {
|
|
|
4584
5331
|
});
|
|
4585
5332
|
}
|
|
4586
5333
|
}
|
|
5334
|
+
/*
|
|
5335
|
+
{
|
|
5336
|
+
id: string,
|
|
5337
|
+
data: BytesHex,
|
|
5338
|
+
srcUrl?: string
|
|
5339
|
+
}
|
|
5340
|
+
*/
|
|
5341
|
+
static fromBytesHex(params) {
|
|
5342
|
+
let data;
|
|
5343
|
+
try {
|
|
5344
|
+
assertRecordStringProperty(params, 'data', 'arg');
|
|
5345
|
+
data = hexToBytesFaster(params.data, true /* strict */);
|
|
5346
|
+
}
|
|
5347
|
+
catch (e) {
|
|
5348
|
+
throw new Error('Invalid public key (deserialization failed)', {
|
|
5349
|
+
cause: e,
|
|
5350
|
+
});
|
|
5351
|
+
}
|
|
5352
|
+
return TFHEPublicKey.fromBytes({
|
|
5353
|
+
id: params?.id,
|
|
5354
|
+
srcUrl: params?.srcUrl,
|
|
5355
|
+
data,
|
|
5356
|
+
});
|
|
5357
|
+
}
|
|
4587
5358
|
/*
|
|
4588
5359
|
{
|
|
4589
5360
|
id: string,
|
|
@@ -4644,6 +5415,20 @@ class TFHEPublicKey {
|
|
|
4644
5415
|
...(this._srcUrl ? { srcUrl: this._srcUrl } : {}),
|
|
4645
5416
|
};
|
|
4646
5417
|
}
|
|
5418
|
+
/*
|
|
5419
|
+
{
|
|
5420
|
+
id: string,
|
|
5421
|
+
data: BytesHex,
|
|
5422
|
+
srcUrl?: string
|
|
5423
|
+
}
|
|
5424
|
+
*/
|
|
5425
|
+
toBytesHex() {
|
|
5426
|
+
return {
|
|
5427
|
+
data: bytesToHexLarge(this._tfheCompactPublicKey.safe_serialize(SERIALIZED_SIZE_LIMIT_PK)),
|
|
5428
|
+
id: this._id,
|
|
5429
|
+
...(this._srcUrl ? { srcUrl: this._srcUrl } : {}),
|
|
5430
|
+
};
|
|
5431
|
+
}
|
|
4647
5432
|
/*
|
|
4648
5433
|
{
|
|
4649
5434
|
publicKey: TFHE.TfheCompactPublicKey
|
|
@@ -4668,6 +5453,75 @@ class TFHEPublicKey {
|
|
|
4668
5453
|
publicKeyId: this._id,
|
|
4669
5454
|
};
|
|
4670
5455
|
}
|
|
5456
|
+
/*
|
|
5457
|
+
{
|
|
5458
|
+
publicKey: Uint8Array
|
|
5459
|
+
publicKeyId: string
|
|
5460
|
+
}
|
|
5461
|
+
*/
|
|
5462
|
+
toPublicKeyBytesHex() {
|
|
5463
|
+
return {
|
|
5464
|
+
publicKey: this.toBytesHex().data,
|
|
5465
|
+
publicKeyId: this._id,
|
|
5466
|
+
};
|
|
5467
|
+
}
|
|
5468
|
+
static _fromPublicKeyBytes(params) {
|
|
5469
|
+
return TFHEPublicKey._fromBytes({
|
|
5470
|
+
data: params.publicKey,
|
|
5471
|
+
id: params.publicKeyId,
|
|
5472
|
+
srcUrl: params.srcUrl,
|
|
5473
|
+
});
|
|
5474
|
+
}
|
|
5475
|
+
static fromPublicKeyBytesHex(params) {
|
|
5476
|
+
try {
|
|
5477
|
+
assertRecordStringProperty(params, 'publicKey', `arg`);
|
|
5478
|
+
assertRecordStringProperty(params, 'publicKeyId', `arg`);
|
|
5479
|
+
return TFHEPublicKey._fromPublicKeyBytes({
|
|
5480
|
+
publicKey: hexToBytesFaster(params.publicKey, true /* strict */),
|
|
5481
|
+
publicKeyId: params.publicKeyId,
|
|
5482
|
+
});
|
|
5483
|
+
}
|
|
5484
|
+
catch (e) {
|
|
5485
|
+
throw new Error('Invalid public key (deserialization failed)', {
|
|
5486
|
+
cause: e,
|
|
5487
|
+
});
|
|
5488
|
+
}
|
|
5489
|
+
}
|
|
5490
|
+
static fromPublicKeyBytes(params) {
|
|
5491
|
+
try {
|
|
5492
|
+
assertUint8ArrayProperty(params, 'publicKey', `arg`);
|
|
5493
|
+
assertRecordStringProperty(params, 'publicKeyId', `arg`);
|
|
5494
|
+
return TFHEPublicKey._fromPublicKeyBytes(params);
|
|
5495
|
+
}
|
|
5496
|
+
catch (e) {
|
|
5497
|
+
throw new Error('Invalid public key (deserialization failed)', {
|
|
5498
|
+
cause: e,
|
|
5499
|
+
});
|
|
5500
|
+
}
|
|
5501
|
+
}
|
|
5502
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
5503
|
+
// JSON
|
|
5504
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
5505
|
+
/*
|
|
5506
|
+
{
|
|
5507
|
+
__type: 'TFHEPublicKey',
|
|
5508
|
+
id: string,
|
|
5509
|
+
data: BytesHex,
|
|
5510
|
+
srcUrl?: string
|
|
5511
|
+
}
|
|
5512
|
+
*/
|
|
5513
|
+
toJSON() {
|
|
5514
|
+
return {
|
|
5515
|
+
__type: 'TFHEPublicKey',
|
|
5516
|
+
...this.toBytesHex(),
|
|
5517
|
+
};
|
|
5518
|
+
}
|
|
5519
|
+
static fromJSON(json) {
|
|
5520
|
+
if (json.__type !== 'TFHEPublicKey') {
|
|
5521
|
+
throw new TFHEPublicKeyError({ message: 'Invalid TFHEPublicKey JSON.' });
|
|
5522
|
+
}
|
|
5523
|
+
return TFHEPublicKey.fromBytesHex(json);
|
|
5524
|
+
}
|
|
4671
5525
|
}
|
|
4672
5526
|
|
|
4673
5527
|
//const __KEY_URL_CACHE__: Record<string, RelayerV2PublicKey> = {};
|
|
@@ -4743,7 +5597,7 @@ class RelayerV2PublicKey {
|
|
|
4743
5597
|
toBytes() {
|
|
4744
5598
|
return {
|
|
4745
5599
|
publicKey: this._publicKey.toBytes(),
|
|
4746
|
-
publicParams: this._crs2048.
|
|
5600
|
+
publicParams: this._crs2048.toPublicParams2048Bytes(),
|
|
4747
5601
|
};
|
|
4748
5602
|
}
|
|
4749
5603
|
}
|
|
@@ -4777,23 +5631,46 @@ class RelayerV2Fhevm extends AbstractRelayerFhevm {
|
|
|
4777
5631
|
get relayerProvider() {
|
|
4778
5632
|
return this._relayerProvider;
|
|
4779
5633
|
}
|
|
5634
|
+
getPublicKeyInfo() {
|
|
5635
|
+
return {
|
|
5636
|
+
id: this._relayerPublicKey.getTFHEPublicKey().id,
|
|
5637
|
+
srcUrl: this._relayerPublicKey.getTFHEPublicKey().srcUrl,
|
|
5638
|
+
};
|
|
5639
|
+
}
|
|
4780
5640
|
getPublicKeyBytes() {
|
|
4781
5641
|
return this._relayerPublicKey.getTFHEPublicKey().toPublicKeyBytes();
|
|
4782
5642
|
}
|
|
4783
5643
|
getPublicKeyWasm() {
|
|
4784
5644
|
return this._relayerPublicKey.getTFHEPublicKey().toPublicKeyWasm();
|
|
4785
5645
|
}
|
|
4786
|
-
|
|
5646
|
+
getPublicParamsBytesForBits(bits) {
|
|
5647
|
+
if (bits === undefined) {
|
|
5648
|
+
throw new TFHECrsError({ message: `Missing PublicParams bits format` });
|
|
5649
|
+
}
|
|
4787
5650
|
if (bits !== 2048) {
|
|
4788
|
-
throw new
|
|
5651
|
+
throw new TFHECrsError({
|
|
5652
|
+
message: `Unsupported PublicParams bits format '${bits}'`,
|
|
5653
|
+
});
|
|
4789
5654
|
}
|
|
4790
|
-
return this._relayerPublicKey.getTFHECrs().
|
|
5655
|
+
return this._relayerPublicKey.getTFHECrs().toPublicParams2048Bytes()['2048'];
|
|
4791
5656
|
}
|
|
4792
|
-
|
|
5657
|
+
getPublicParamsWasmForBits(bits) {
|
|
5658
|
+
if (bits === undefined) {
|
|
5659
|
+
throw new TFHECrsError({ message: `Missing PublicParams bits format` });
|
|
5660
|
+
}
|
|
4793
5661
|
if (bits !== 2048) {
|
|
4794
|
-
throw new
|
|
5662
|
+
throw new TFHECrsError({
|
|
5663
|
+
message: `Unsupported PublicParams bits format '${bits}'`,
|
|
5664
|
+
});
|
|
4795
5665
|
}
|
|
4796
|
-
return this._relayerPublicKey.getTFHECrs().
|
|
5666
|
+
return this._relayerPublicKey.getTFHECrs().toPublicParams2048Wasm()['2048'];
|
|
5667
|
+
}
|
|
5668
|
+
getPublicParamsInfo() {
|
|
5669
|
+
return {
|
|
5670
|
+
id: this._relayerPublicKey.getTFHECrs().id,
|
|
5671
|
+
bits: this._relayerPublicKey.getTFHECrs().bits,
|
|
5672
|
+
srcUrl: this._relayerPublicKey.getTFHECrs().srcUrl,
|
|
5673
|
+
};
|
|
4797
5674
|
}
|
|
4798
5675
|
}
|
|
4799
5676
|
|
|
@@ -4832,24 +5709,42 @@ class RelayerV1Fhevm extends AbstractRelayerFhevm {
|
|
|
4832
5709
|
publicKeyId: this._publicKeyData.publicKeyId,
|
|
4833
5710
|
};
|
|
4834
5711
|
}
|
|
5712
|
+
getPublicKeyInfo() {
|
|
5713
|
+
return {
|
|
5714
|
+
id: this._publicKeyData.publicKeyId,
|
|
5715
|
+
};
|
|
5716
|
+
}
|
|
5717
|
+
getPublicParamsInfo() {
|
|
5718
|
+
return {
|
|
5719
|
+
id: this._publicParamsData['2048'].publicParamsId,
|
|
5720
|
+
bits: 2048,
|
|
5721
|
+
};
|
|
5722
|
+
}
|
|
4835
5723
|
getPublicKeyWasm() {
|
|
4836
5724
|
return {
|
|
4837
5725
|
publicKey: this._publicKeyData.publicKey,
|
|
4838
5726
|
publicKeyId: this._publicKeyData.publicKeyId,
|
|
4839
5727
|
};
|
|
4840
5728
|
}
|
|
4841
|
-
|
|
5729
|
+
getPublicParamsBytesForBits(bits) {
|
|
5730
|
+
if (bits === undefined) {
|
|
5731
|
+
throw new Error(`Missing PublicParams bits format`);
|
|
5732
|
+
}
|
|
4842
5733
|
if (bits !== 2048) {
|
|
4843
|
-
throw new Error(`Unsupported PublicParams bits format ${bits}`);
|
|
5734
|
+
throw new Error(`Unsupported PublicParams bits format '${bits}'`);
|
|
4844
5735
|
}
|
|
4845
|
-
|
|
5736
|
+
const res = {
|
|
4846
5737
|
publicParams: this._publicParamsData['2048'].publicParams.safe_serialize(SERIALIZED_SIZE_LIMIT_CRS),
|
|
4847
5738
|
publicParamsId: this._publicParamsData['2048'].publicParamsId,
|
|
4848
5739
|
};
|
|
5740
|
+
return res;
|
|
4849
5741
|
}
|
|
4850
|
-
|
|
5742
|
+
getPublicParamsWasmForBits(bits) {
|
|
5743
|
+
if (bits === undefined) {
|
|
5744
|
+
throw new Error(`Missing PublicParams bits format`);
|
|
5745
|
+
}
|
|
4851
5746
|
if (bits !== 2048) {
|
|
4852
|
-
throw new Error(`Unsupported PublicParams bits format ${bits}`);
|
|
5747
|
+
throw new Error(`Unsupported PublicParams bits format '${bits}'`);
|
|
4853
5748
|
}
|
|
4854
5749
|
return {
|
|
4855
5750
|
publicParams: this._publicParamsData['2048'].publicParams,
|
|
@@ -4870,11 +5765,16 @@ async function createRelayerFhevm(config) {
|
|
|
4870
5765
|
publicParams: config.publicParams,
|
|
4871
5766
|
});
|
|
4872
5767
|
}
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
5768
|
+
else if (resolved.version === 1) {
|
|
5769
|
+
return RelayerV1Fhevm.fromConfig({
|
|
5770
|
+
relayerVersionUrl: resolved.url,
|
|
5771
|
+
publicKey: config.publicKey,
|
|
5772
|
+
publicParams: config.publicParams,
|
|
5773
|
+
});
|
|
5774
|
+
}
|
|
5775
|
+
else {
|
|
5776
|
+
throw new Error(`Invalid relayerUrl: ${config.relayerUrl}`);
|
|
5777
|
+
}
|
|
4878
5778
|
}
|
|
4879
5779
|
function _resolveRelayerUrl(value, defaultVersion) {
|
|
4880
5780
|
if (!value || typeof value !== 'string') {
|
|
@@ -4905,60 +5805,39 @@ function _resolveRelayerUrl(value, defaultVersion) {
|
|
|
4905
5805
|
};
|
|
4906
5806
|
}
|
|
4907
5807
|
|
|
4908
|
-
|
|
4909
|
-
|
|
4910
|
-
|
|
4911
|
-
|
|
4912
|
-
|
|
4913
|
-
|
|
4914
|
-
|
|
4915
|
-
|
|
4916
|
-
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
* | 8 | 2 | `euint8` | |
|
|
4922
|
-
* | 16 | 3 | `euint16` | |
|
|
4923
|
-
* | 32 | 4 | `euint32` | |
|
|
4924
|
-
* | 64 | 5 | `euint64` | |
|
|
4925
|
-
* | 128 | 6 | `euint128` | |
|
|
4926
|
-
* | 160 | 7 | `eaddress` | Used for encrypted Ethereum addresses. |
|
|
4927
|
-
* | 256 | 8 | `euint256` | The maximum supported integer size. |
|
|
4928
|
-
*/
|
|
4929
|
-
const ENCRYPTION_TYPES = {
|
|
4930
|
-
2: 0, // ebool (FheTypeId=0) is using 2 encrypted bits
|
|
4931
|
-
// euint4 (FheTypeId=1) is deprecated
|
|
4932
|
-
8: 2, // euint8 (FheTypeId=2) is using 8 encrypted bits
|
|
4933
|
-
16: 3, // euint16 (FheTypeId=3) is using 16 encrypted bits
|
|
4934
|
-
32: 4, // euint32 (FheTypeId=4) is using 32 encrypted bits
|
|
4935
|
-
64: 5, // euint64 (FheTypeId=5) is using 64 encrypted bits
|
|
4936
|
-
128: 6, // euint128 (FheTypeId=128) is using 128 encrypted bits
|
|
4937
|
-
160: 7, // eaddress (FheTypeId=7) is using 160 encrypted bits
|
|
4938
|
-
256: 8, // euint256 (FheTypeId=8) is using 256 encrypted bits
|
|
5808
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
5809
|
+
// MainnetConfig
|
|
5810
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
5811
|
+
const MainnetConfig = {
|
|
5812
|
+
aclContractAddress: '0xcA2E8f1F656CD25C01F05d0b243Ab1ecd4a8ffb6',
|
|
5813
|
+
kmsContractAddress: '0x77627828a55156b04Ac0DC0eb30467f1a552BB03',
|
|
5814
|
+
inputVerifierContractAddress: '0xCe0FC2e05CFff1B719EFF7169f7D80Af770c8EA2',
|
|
5815
|
+
verifyingContractAddressDecryption: '0x0f6024a97684f7d90ddb0fAAD79cB15F2C888D24',
|
|
5816
|
+
verifyingContractAddressInputVerification: '0xcB1bB072f38bdAF0F328CdEf1Fc6eDa1DF029287',
|
|
5817
|
+
chainId: 1,
|
|
5818
|
+
gatewayChainId: 261131,
|
|
5819
|
+
network: 'https://ethereum-rpc.publicnode.com',
|
|
5820
|
+
relayerUrl: 'https://relayer.mainnet.zama.org',
|
|
4939
5821
|
};
|
|
4940
|
-
|
|
5822
|
+
Object.freeze(MainnetConfig);
|
|
5823
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
5824
|
+
// SepoliaConfig
|
|
5825
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
4941
5826
|
const SepoliaConfig = {
|
|
4942
|
-
// ACL_CONTRACT_ADDRESS (FHEVM Host chain)
|
|
4943
5827
|
aclContractAddress: '0xf0Ffdc93b7E186bC2f8CB3dAA75D86d1930A433D',
|
|
4944
|
-
// KMS_VERIFIER_CONTRACT_ADDRESS (FHEVM Host chain)
|
|
4945
5828
|
kmsContractAddress: '0xbE0E383937d564D7FF0BC3b46c51f0bF8d5C311A',
|
|
4946
|
-
// INPUT_VERIFIER_CONTRACT_ADDRESS (FHEVM Host chain)
|
|
4947
5829
|
inputVerifierContractAddress: '0xBBC1fFCdc7C316aAAd72E807D9b0272BE8F84DA0',
|
|
4948
|
-
// DECRYPTION_ADDRESS (Gateway chain)
|
|
4949
5830
|
verifyingContractAddressDecryption: '0x5D8BD78e2ea6bbE41f26dFe9fdaEAa349e077478',
|
|
4950
|
-
// INPUT_VERIFICATION_ADDRESS (Gateway chain)
|
|
4951
5831
|
verifyingContractAddressInputVerification: '0x483b9dE06E4E4C7D35CCf5837A1668487406D955',
|
|
4952
|
-
// FHEVM Host chain id
|
|
4953
5832
|
chainId: 11155111,
|
|
4954
|
-
// Gateway chain id
|
|
4955
5833
|
gatewayChainId: 10901,
|
|
4956
|
-
// Optional RPC provider to host chain
|
|
4957
5834
|
network: 'https://ethereum-sepolia-rpc.publicnode.com',
|
|
4958
|
-
// Relayer URL
|
|
4959
5835
|
relayerUrl: 'https://relayer.testnet.zama.org',
|
|
4960
5836
|
};
|
|
4961
5837
|
Object.freeze(SepoliaConfig);
|
|
5838
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
5839
|
+
// createInstance
|
|
5840
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
4962
5841
|
const createInstance = async (config) => {
|
|
4963
5842
|
const { verifyingContractAddressDecryption, verifyingContractAddressInputVerification, publicKey, inputVerifierContractAddress, kmsContractAddress, aclContractAddress, gatewayChainId, auth, } = config;
|
|
4964
5843
|
if (!isChecksummedAddress(aclContractAddress)) {
|
|
@@ -4990,29 +5869,33 @@ const createInstance = async (config) => {
|
|
|
4990
5869
|
defaultRelayerVersion: 1,
|
|
4991
5870
|
});
|
|
4992
5871
|
const chainId = await getChainId(provider, config);
|
|
4993
|
-
// const relayerVersionUrl = `${config.relayerUrl!}/v1`;
|
|
4994
|
-
// const publicKeyData = await getTfheCompactPublicKey({
|
|
4995
|
-
// relayerVersionUrl: relayerFhevm.relayerVersionUrl,
|
|
4996
|
-
// publicKey: config.publicKey,
|
|
4997
|
-
// });
|
|
4998
|
-
//const aaa = relayerFhevm.getPublicKey();
|
|
4999
|
-
// const publicParamsData = await getPublicParams({
|
|
5000
|
-
// relayerVersionUrl,
|
|
5001
|
-
// publicParams: config.publicParams,
|
|
5002
|
-
// });
|
|
5003
5872
|
const kmsSigners = await getKMSSigners(provider, kmsContractAddress);
|
|
5004
5873
|
const thresholdKMSSigners = await getKMSSignersThreshold(provider, kmsContractAddress);
|
|
5005
5874
|
const coprocessorSigners = await getCoprocessorSigners(provider, inputVerifierContractAddress);
|
|
5006
5875
|
const thresholdCoprocessorSigners = await getCoprocessorSignersThreshold(provider, inputVerifierContractAddress);
|
|
5007
5876
|
return {
|
|
5008
|
-
createEncryptedInput: createRelayerEncryptedInput(aclContractAddress, verifyingContractAddressInputVerification, chainId, gatewayChainId,
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
|
|
5877
|
+
createEncryptedInput: createRelayerEncryptedInput(aclContractAddress, verifyingContractAddressInputVerification, chainId, gatewayChainId, relayerFhevm.relayerProvider, relayerFhevm.getPublicKeyWasm().publicKey, { 2048: relayerFhevm.getPublicParamsWasmForBits(2048) }, coprocessorSigners, thresholdCoprocessorSigners, auth && { auth }),
|
|
5878
|
+
requestZKProofVerification: (zkProof, options) => {
|
|
5879
|
+
if (zkProof.chainId !== chainId ||
|
|
5880
|
+
zkProof.aclContractAddress !== aclContractAddress) {
|
|
5881
|
+
throw new Error('Invalid ZKProof');
|
|
5882
|
+
}
|
|
5883
|
+
return requestCiphertextWithZKProofVerification({
|
|
5884
|
+
ciphertext: zkProof.ciphertextWithZkProof,
|
|
5885
|
+
aclContractAddress: aclContractAddress,
|
|
5886
|
+
contractAddress: zkProof.contractAddress,
|
|
5887
|
+
userAddress: zkProof.userAddress,
|
|
5888
|
+
chainId,
|
|
5889
|
+
gatewayChainId,
|
|
5890
|
+
bits: zkProof.bits,
|
|
5891
|
+
coprocessorSigners,
|
|
5892
|
+
extraData: '0x00',
|
|
5893
|
+
thresholdCoprocessorSigners,
|
|
5894
|
+
relayerProvider: relayerFhevm.relayerProvider,
|
|
5895
|
+
verifyingContractAddressInputVerification: verifyingContractAddressInputVerification,
|
|
5896
|
+
options,
|
|
5897
|
+
});
|
|
5898
|
+
},
|
|
5016
5899
|
generateKeypair,
|
|
5017
5900
|
createEIP712: createEIP712(verifyingContractAddressDecryption, chainId),
|
|
5018
5901
|
publicDecrypt: publicDecryptRequest(kmsSigners, thresholdKMSSigners, gatewayChainId, verifyingContractAddressDecryption, aclContractAddress,
|
|
@@ -5022,7 +5905,7 @@ const createInstance = async (config) => {
|
|
|
5022
5905
|
//cleanURL(config.relayerUrl),
|
|
5023
5906
|
relayerFhevm.relayerProvider, provider, auth && { auth }),
|
|
5024
5907
|
getPublicKey: () => relayerFhevm.getPublicKeyBytes(),
|
|
5025
|
-
getPublicParams: (bits) => relayerFhevm.
|
|
5908
|
+
getPublicParams: (bits) => relayerFhevm.getPublicParamsBytesForBits(bits),
|
|
5026
5909
|
// getPublicKey: () =>
|
|
5027
5910
|
// publicKeyData.publicKey
|
|
5028
5911
|
// ? {
|
|
@@ -5060,13 +5943,13 @@ const createTfheKeypair = () => {
|
|
|
5060
5943
|
};
|
|
5061
5944
|
const createTfhePublicKey = () => {
|
|
5062
5945
|
const { publicKey } = createTfheKeypair();
|
|
5063
|
-
return
|
|
5946
|
+
return bytesToHexNo0x(publicKey.serialize());
|
|
5064
5947
|
};
|
|
5065
5948
|
|
|
5066
5949
|
global.TFHE = TFHEPkg__namespace;
|
|
5067
5950
|
global.TKMS = TKMSPkg__namespace;
|
|
5068
5951
|
|
|
5069
|
-
exports.
|
|
5952
|
+
exports.MainnetConfig = MainnetConfig;
|
|
5070
5953
|
exports.SepoliaConfig = SepoliaConfig;
|
|
5071
5954
|
exports.createEIP712 = createEIP712;
|
|
5072
5955
|
exports.createInstance = createInstance;
|