@zama-fhe/relayer-sdk 0.4.0-alpha.1 → 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 +5902 -5206
- package/bundle/relayer-sdk-js.umd.cjs +5 -5
- package/lib/internal.js +6138 -0
- package/lib/node.cjs +1061 -215
- package/lib/node.d.ts +8 -1
- package/lib/node.js +1061 -215
- package/lib/web.d.ts +8 -1
- package/lib/web.js +1060 -214
- package/package.json +1 -1
package/lib/node.cjs
CHANGED
|
@@ -29,7 +29,7 @@ const SERIALIZED_SIZE_LIMIT_PK = BigInt(1024 * 1024 * 512);
|
|
|
29
29
|
const SERIALIZED_SIZE_LIMIT_CRS = BigInt(1024 * 1024 * 512);
|
|
30
30
|
|
|
31
31
|
// This file is auto-generated
|
|
32
|
-
const version = '0.4.0-alpha.
|
|
32
|
+
const version = '0.4.0-alpha.2';
|
|
33
33
|
const sdkName = '@zama-fhe/relayer-sdk';
|
|
34
34
|
|
|
35
35
|
function getErrorCause(e) {
|
|
@@ -831,9 +831,9 @@ function assertRecordStringArrayProperty(o, property, objName) {
|
|
|
831
831
|
}
|
|
832
832
|
}
|
|
833
833
|
}
|
|
834
|
-
function safeJSONstringify(o) {
|
|
834
|
+
function safeJSONstringify(o, space) {
|
|
835
835
|
try {
|
|
836
|
-
return JSON.stringify(o, (_, v) => typeof v === 'bigint' ? v.toString() : v);
|
|
836
|
+
return JSON.stringify(o, (_, v) => (typeof v === 'bigint' ? v.toString() : v), space);
|
|
837
837
|
}
|
|
838
838
|
catch {
|
|
839
839
|
return '';
|
|
@@ -949,6 +949,17 @@ const NumEncryptedBits = {
|
|
|
949
949
|
7: 160, // eaddress
|
|
950
950
|
8: 256, // euint256
|
|
951
951
|
};
|
|
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
|
+
// }
|
|
952
963
|
function checkEncryptedBits(handles) {
|
|
953
964
|
let total = 0;
|
|
954
965
|
for (const handle of handles) {
|
|
@@ -1006,7 +1017,7 @@ function isBytes(value, bytewidth) {
|
|
|
1006
1017
|
if (!(value instanceof Uint8Array)) {
|
|
1007
1018
|
return false;
|
|
1008
1019
|
}
|
|
1009
|
-
return value.length === bytewidth ;
|
|
1020
|
+
return bytewidth ? value.length === bytewidth : true;
|
|
1010
1021
|
}
|
|
1011
1022
|
function isBytesHex(value, bytewidth) {
|
|
1012
1023
|
if (!is0x(value)) {
|
|
@@ -1239,6 +1250,54 @@ function assertUint8ArrayProperty(o, property, objName) {
|
|
|
1239
1250
|
});
|
|
1240
1251
|
}
|
|
1241
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
|
+
]);
|
|
1242
1301
|
/**
|
|
1243
1302
|
* Convert a Uint8Array to a hex string (without 0x prefix).
|
|
1244
1303
|
*/
|
|
@@ -1258,15 +1317,49 @@ function bytesToHexNo0x(bytes) {
|
|
|
1258
1317
|
function bytesToHex(bytes) {
|
|
1259
1318
|
return `0x${bytesToHexNo0x(bytes)}`;
|
|
1260
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
|
+
}
|
|
1261
1331
|
/**
|
|
1262
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]
|
|
1263
1336
|
*/
|
|
1264
1337
|
function hexToBytes(hexString) {
|
|
1338
|
+
if (hexString.length % 2 !== 0) {
|
|
1339
|
+
throw new Error('Invalid hex string: odd length');
|
|
1340
|
+
}
|
|
1265
1341
|
const arr = hexString.replace(/^(0x)/, '').match(/.{1,2}/g);
|
|
1266
1342
|
if (!arr)
|
|
1267
1343
|
return new Uint8Array();
|
|
1268
1344
|
return Uint8Array.from(arr.map((byte) => parseInt(byte, 16)));
|
|
1269
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
|
+
}
|
|
1270
1363
|
/**
|
|
1271
1364
|
* Convert a Uint8Array to a bigint
|
|
1272
1365
|
*/
|
|
@@ -1280,9 +1373,6 @@ function bytesToBigInt(byteArray) {
|
|
|
1280
1373
|
}
|
|
1281
1374
|
return result;
|
|
1282
1375
|
}
|
|
1283
|
-
function toHexString(bytes, with0x = false) {
|
|
1284
|
-
return `${with0x ? '0x' : ''}${bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '')}`;
|
|
1285
|
-
}
|
|
1286
1376
|
async function fetchBytes(url) {
|
|
1287
1377
|
const response = await fetch(url);
|
|
1288
1378
|
if (!response.ok) {
|
|
@@ -1374,8 +1464,8 @@ const userDecryptRequest = (kmsSigners, gatewayChainId, chainId, verifyingContra
|
|
|
1374
1464
|
const publicKeySanitized = publicKey.replace(/^(0x)/, '');
|
|
1375
1465
|
const handleContractPairs = _handles.map((h) => ({
|
|
1376
1466
|
handle: typeof h.handle === 'string'
|
|
1377
|
-
?
|
|
1378
|
-
:
|
|
1467
|
+
? bytesToHex(hexToBytes(h.handle))
|
|
1468
|
+
: bytesToHex(h.handle),
|
|
1379
1469
|
contractAddress: getAddress$1(h.contractAddress),
|
|
1380
1470
|
}));
|
|
1381
1471
|
checkEncryptedBits(handleContractPairs.map((h) => h.handle));
|
|
@@ -1591,9 +1681,8 @@ const createEncryptedInput = ({ aclContractAddress, chainId, tfheCompactPublicKe
|
|
|
1591
1681
|
|
|
1592
1682
|
const MAX_UINT64 = BigInt('18446744073709551615'); // 2^64 - 1
|
|
1593
1683
|
BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff');
|
|
1594
|
-
const MAX_UINT32 = 0xffffffff;
|
|
1595
1684
|
const MAX_UINT8 = 0xff;
|
|
1596
|
-
function
|
|
1685
|
+
function numberToHexNo0x(num) {
|
|
1597
1686
|
let hex = num.toString(16);
|
|
1598
1687
|
return hex.length % 2 ? '0' + hex : hex;
|
|
1599
1688
|
}
|
|
@@ -1627,25 +1716,19 @@ function isUint8(value) {
|
|
|
1627
1716
|
}
|
|
1628
1717
|
return value <= MAX_UINT8;
|
|
1629
1718
|
}
|
|
1630
|
-
function isUint32(value) {
|
|
1631
|
-
if (!isUint(value)) {
|
|
1632
|
-
return false;
|
|
1633
|
-
}
|
|
1634
|
-
return value <= MAX_UINT32;
|
|
1635
|
-
}
|
|
1636
1719
|
function isUint64(value) {
|
|
1637
1720
|
if (!isUint(value)) {
|
|
1638
1721
|
return false;
|
|
1639
1722
|
}
|
|
1640
1723
|
return value <= MAX_UINT64;
|
|
1641
1724
|
}
|
|
1642
|
-
function
|
|
1643
|
-
if (!
|
|
1644
|
-
throw new InvalidTypeError({ expectedType: '
|
|
1725
|
+
function numberToBytes32(num) {
|
|
1726
|
+
if (!isUintNumber(num)) {
|
|
1727
|
+
throw new InvalidTypeError({ expectedType: 'Uint' });
|
|
1645
1728
|
}
|
|
1646
1729
|
const buffer = new ArrayBuffer(32);
|
|
1647
1730
|
const view = new DataView(buffer);
|
|
1648
|
-
view.
|
|
1731
|
+
view.setBigUint64(24, BigInt(num), false);
|
|
1649
1732
|
return new Uint8Array(buffer);
|
|
1650
1733
|
}
|
|
1651
1734
|
function assertIsUint8(value) {
|
|
@@ -1743,63 +1826,213 @@ function checksummedAddressToBytes20(address) {
|
|
|
1743
1826
|
class FhevmHandleError extends RelayerErrorBase {
|
|
1744
1827
|
constructor({ handle, message }) {
|
|
1745
1828
|
super({
|
|
1746
|
-
message: message ??
|
|
1829
|
+
message: message ??
|
|
1830
|
+
(handle
|
|
1831
|
+
? `FHEVM Handle "${handle}" is invalid.`
|
|
1832
|
+
: `FHEVM Handle is invalid.`),
|
|
1747
1833
|
name: 'FhevmHandleError',
|
|
1748
1834
|
});
|
|
1749
1835
|
}
|
|
1750
1836
|
}
|
|
1751
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
|
+
|
|
1752
1995
|
////////////////////////////////////////////////////////////////////////////////
|
|
1753
1996
|
// FhevmHandle
|
|
1754
1997
|
////////////////////////////////////////////////////////////////////////////////
|
|
1755
1998
|
class FhevmHandle {
|
|
1999
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2000
|
+
// Instance Properties
|
|
2001
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
1756
2002
|
_hash21;
|
|
1757
2003
|
_chainId;
|
|
1758
2004
|
_fheTypeId;
|
|
1759
2005
|
_version;
|
|
1760
2006
|
_computed;
|
|
1761
2007
|
_index;
|
|
2008
|
+
_handleBytes32Hex;
|
|
2009
|
+
_handleBytes32;
|
|
2010
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2011
|
+
// Static Constants
|
|
2012
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
1762
2013
|
static RAW_CT_HASH_DOMAIN_SEPARATOR = 'ZK-w_rct';
|
|
1763
2014
|
static HANDLE_HASH_DOMAIN_SEPARATOR = 'ZK-w_hdl';
|
|
1764
|
-
static
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
static FheTypeEncryptionBitwidthsToId = {
|
|
1775
|
-
2: 0,
|
|
1776
|
-
8: 2,
|
|
1777
|
-
16: 3,
|
|
1778
|
-
32: 4,
|
|
1779
|
-
64: 5,
|
|
1780
|
-
128: 6,
|
|
1781
|
-
160: 7,
|
|
1782
|
-
256: 8,
|
|
1783
|
-
};
|
|
1784
|
-
static FheTypeIdToSolidityPrimitiveType = {
|
|
1785
|
-
0: 'bool',
|
|
1786
|
-
2: 'uint256',
|
|
1787
|
-
3: 'uint256',
|
|
1788
|
-
4: 'uint256',
|
|
1789
|
-
5: 'uint256',
|
|
1790
|
-
6: 'uint256',
|
|
1791
|
-
7: 'address',
|
|
1792
|
-
8: 'uint256',
|
|
1793
|
-
};
|
|
1794
|
-
static {
|
|
1795
|
-
Object.freeze(FhevmHandle.FheTypeIdToEncryptionBitwidths);
|
|
1796
|
-
Object.freeze(FhevmHandle.FheTypeEncryptionBitwidthsToId);
|
|
1797
|
-
}
|
|
1798
|
-
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
|
+
}
|
|
1799
2025
|
if (BigInt(chainId) > MAX_UINT64) {
|
|
1800
2026
|
// fhevm assumes chainID is only taking up to 8 bytes
|
|
1801
|
-
throw new
|
|
2027
|
+
throw new FhevmHandleError({
|
|
2028
|
+
message: 'ChainId exceeds maximum allowed value (8 bytes)',
|
|
2029
|
+
});
|
|
2030
|
+
}
|
|
2031
|
+
if (!isBytesHex(hash21, 21)) {
|
|
2032
|
+
throw new FhevmHandleError({ message: 'Hash21 should be 21 bytes long' });
|
|
1802
2033
|
}
|
|
2034
|
+
this._handleBytes32 = handleBytes32;
|
|
2035
|
+
this._handleBytes32Hex = handleBytes32Hex;
|
|
1803
2036
|
this._hash21 = hash21;
|
|
1804
2037
|
this._chainId = chainId;
|
|
1805
2038
|
this._fheTypeId = fheTypeId;
|
|
@@ -1809,6 +2042,9 @@ class FhevmHandle {
|
|
|
1809
2042
|
this._index = index;
|
|
1810
2043
|
}
|
|
1811
2044
|
}
|
|
2045
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2046
|
+
// Instance Getters
|
|
2047
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
1812
2048
|
get hash21() {
|
|
1813
2049
|
return this._hash21;
|
|
1814
2050
|
}
|
|
@@ -1818,6 +2054,9 @@ class FhevmHandle {
|
|
|
1818
2054
|
get fheTypeId() {
|
|
1819
2055
|
return this._fheTypeId;
|
|
1820
2056
|
}
|
|
2057
|
+
get fheTypeName() {
|
|
2058
|
+
return fheTypeNameFromId(this._fheTypeId);
|
|
2059
|
+
}
|
|
1821
2060
|
get version() {
|
|
1822
2061
|
return this._version;
|
|
1823
2062
|
}
|
|
@@ -1827,6 +2066,106 @@ class FhevmHandle {
|
|
|
1827
2066
|
get index() {
|
|
1828
2067
|
return this._index;
|
|
1829
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
|
+
}
|
|
1830
2169
|
static fromZKProof(params) {
|
|
1831
2170
|
assertIsChecksummedAddress(params.aclAddress);
|
|
1832
2171
|
assertIsUint64(params.chainId);
|
|
@@ -1836,7 +2175,7 @@ class FhevmHandle {
|
|
|
1836
2175
|
fheTypeIds = params.fheTypeIds;
|
|
1837
2176
|
}
|
|
1838
2177
|
else if (params.fheTypeEncryptionBitwidths !== undefined) {
|
|
1839
|
-
fheTypeIds = params.fheTypeEncryptionBitwidths.map((w) =>
|
|
2178
|
+
fheTypeIds = params.fheTypeEncryptionBitwidths.map((w) => fheTypeIdFromEncryptionBits(w));
|
|
1840
2179
|
}
|
|
1841
2180
|
else {
|
|
1842
2181
|
throw new InternalError({
|
|
@@ -1867,22 +2206,69 @@ class FhevmHandle {
|
|
|
1867
2206
|
const handles = [];
|
|
1868
2207
|
for (let i = 0; i < fheTypeIds.length; ++i) {
|
|
1869
2208
|
const hash21 = FhevmHandle._computeInputHash21(hexToBytes(blobHashBytes32Hex), params.aclAddress, params.chainId, i);
|
|
1870
|
-
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
|
+
}));
|
|
1871
2217
|
}
|
|
1872
2218
|
return handles;
|
|
1873
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
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
1874
2260
|
/**
|
|
1875
2261
|
* blobHashBytes32 = keccak256(ciphertextWithZKProof)
|
|
1876
2262
|
*/
|
|
1877
2263
|
static _computeInputHash21(blobHashBytes32, aclAddress, chainId, index) {
|
|
1878
2264
|
/*
|
|
1879
2265
|
https://github.com/zama-ai/fhevm/blob/8ffbd5906ab3d57af178e049930e3fc065c9d4b3/coprocessor/fhevm-engine/zkproof-worker/src/verifier.rs#L431C7-L431C8
|
|
1880
|
-
|
|
2266
|
+
|
|
1881
2267
|
handle_hash = Bytes("ZK-w_hdl") + blobHash 32 Bytes + index 1 Byte + aclAddress 20 Bytes + chainId 32 bytes
|
|
1882
2268
|
===========================================================================================================
|
|
1883
2269
|
|
|
1884
2270
|
const HANDLE_HASH_DOMAIN_SEPARATOR: [u8; 8] = *b"ZK-w_hdl";
|
|
1885
|
-
|
|
2271
|
+
|
|
1886
2272
|
let mut handle_hash = Keccak256::new();
|
|
1887
2273
|
handle_hash.update(HANDLE_HASH_DOMAIN_SEPARATOR);
|
|
1888
2274
|
handle_hash.update(blob_hash);
|
|
@@ -1903,62 +2289,12 @@ class FhevmHandle {
|
|
|
1903
2289
|
assertIsUint64(chainId);
|
|
1904
2290
|
const encryptionIndexByte1 = new Uint8Array([index]);
|
|
1905
2291
|
const aclContractAddressBytes20 = checksummedAddressToBytes20(aclAddress);
|
|
1906
|
-
const chainIdBytes32 =
|
|
2292
|
+
const chainIdBytes32 = numberToBytes32(chainId);
|
|
1907
2293
|
const encoder = new TextEncoder();
|
|
1908
2294
|
const domainSepBytes = encoder.encode(FhevmHandle.HANDLE_HASH_DOMAIN_SEPARATOR);
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
assertRelayer((this._index === undefined && this._computed) ||
|
|
1913
|
-
(this._index !== undefined && this._index < 255 && !this._computed));
|
|
1914
|
-
const chainId32Bytes = uint32ToBytes32(this._chainId);
|
|
1915
|
-
const chainId8Bytes = chainId32Bytes.subarray(24, 32);
|
|
1916
|
-
const handleHash = hexToBytes(this._hash21);
|
|
1917
|
-
const handleBytes32AsBytes = new Uint8Array(32);
|
|
1918
|
-
handleBytes32AsBytes.set(handleHash, 0);
|
|
1919
|
-
handleBytes32AsBytes[21] = this._index === undefined ? 255 : this._index;
|
|
1920
|
-
handleBytes32AsBytes.set(chainId8Bytes, 22);
|
|
1921
|
-
handleBytes32AsBytes[30] = this._fheTypeId;
|
|
1922
|
-
handleBytes32AsBytes[31] = this._version;
|
|
1923
|
-
return handleBytes32AsBytes;
|
|
1924
|
-
}
|
|
1925
|
-
toBytes32Hex() {
|
|
1926
|
-
return bytesToHex(this.toBytes32());
|
|
1927
|
-
}
|
|
1928
|
-
static checkHandleHex(handle) {
|
|
1929
|
-
if (!isBytes32Hex(handle)) {
|
|
1930
|
-
throw new FhevmHandleError({ handle });
|
|
1931
|
-
}
|
|
1932
|
-
}
|
|
1933
|
-
static isFheTypeId(value) {
|
|
1934
|
-
switch (value) {
|
|
1935
|
-
case 0:
|
|
1936
|
-
// 1: euint4 is deprecated
|
|
1937
|
-
case 2:
|
|
1938
|
-
case 3:
|
|
1939
|
-
case 4:
|
|
1940
|
-
case 5:
|
|
1941
|
-
case 6:
|
|
1942
|
-
case 7:
|
|
1943
|
-
case 8:
|
|
1944
|
-
return true;
|
|
1945
|
-
default:
|
|
1946
|
-
return false;
|
|
1947
|
-
}
|
|
1948
|
-
}
|
|
1949
|
-
static getFheTypeId(handle) {
|
|
1950
|
-
if (!isBytes32Hex(handle)) {
|
|
1951
|
-
throw new FhevmHandleError({ handle });
|
|
1952
|
-
}
|
|
1953
|
-
const hexPair = handle.slice(-4, -2).toLowerCase();
|
|
1954
|
-
const typeDiscriminant = parseInt(hexPair, 16);
|
|
1955
|
-
if (!FhevmHandle.isFheTypeId(typeDiscriminant)) {
|
|
1956
|
-
throw new FhevmHandleError({
|
|
1957
|
-
handle,
|
|
1958
|
-
message: `FHEVM Handle "${handle}" is invalid. Unknown FheType: ${typeDiscriminant}`,
|
|
1959
|
-
});
|
|
1960
|
-
}
|
|
1961
|
-
return typeDiscriminant;
|
|
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);
|
|
1962
2298
|
}
|
|
1963
2299
|
}
|
|
1964
2300
|
|
|
@@ -1967,6 +2303,89 @@ const getAddress = (value) => ethers.getAddress(value);
|
|
|
1967
2303
|
const currentCiphertextVersion = () => {
|
|
1968
2304
|
return 0;
|
|
1969
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
|
+
}
|
|
1970
2389
|
function isThresholdReached$1(coprocessorSigners, recoveredAddresses, threshold) {
|
|
1971
2390
|
const addressMap = new Map();
|
|
1972
2391
|
recoveredAddresses.forEach((address, index) => {
|
|
@@ -2050,8 +2469,15 @@ const createRelayerEncryptedInput = (aclContractAddress, verifyingContractAddres
|
|
|
2050
2469
|
getBits() {
|
|
2051
2470
|
return input.getBits();
|
|
2052
2471
|
},
|
|
2053
|
-
|
|
2054
|
-
return
|
|
2472
|
+
generateZKProof() {
|
|
2473
|
+
return {
|
|
2474
|
+
chainId,
|
|
2475
|
+
aclContractAddress: aclContractAddress,
|
|
2476
|
+
userAddress: userAddress,
|
|
2477
|
+
contractAddress: contractAddress,
|
|
2478
|
+
ciphertextWithZkProof: input.encrypt(),
|
|
2479
|
+
bits: input.getBits(),
|
|
2480
|
+
};
|
|
2055
2481
|
},
|
|
2056
2482
|
encrypt: async (options) => {
|
|
2057
2483
|
const extraData = '0x00';
|
|
@@ -2060,7 +2486,7 @@ const createRelayerEncryptedInput = (aclContractAddress, verifyingContractAddres
|
|
|
2060
2486
|
const payload = {
|
|
2061
2487
|
contractAddress: getAddress(contractAddress),
|
|
2062
2488
|
userAddress: getAddress(userAddress),
|
|
2063
|
-
ciphertextWithInputVerification:
|
|
2489
|
+
ciphertextWithInputVerification: bytesToHexNo0x(ciphertext),
|
|
2064
2490
|
contractChainId: ('0x' + chainId.toString(16)),
|
|
2065
2491
|
extraData,
|
|
2066
2492
|
};
|
|
@@ -2089,8 +2515,8 @@ const createRelayerEncryptedInput = (aclContractAddress, verifyingContractAddres
|
|
|
2089
2515
|
for (let index = 0; index < handles.length; index += 1) {
|
|
2090
2516
|
let handle = handles[index];
|
|
2091
2517
|
let responseHandle = responseHandles[index];
|
|
2092
|
-
let expected =
|
|
2093
|
-
let current =
|
|
2518
|
+
let expected = bytesToHexNo0x(handle);
|
|
2519
|
+
let current = bytesToHexNo0x(responseHandle);
|
|
2094
2520
|
if (expected !== current) {
|
|
2095
2521
|
throw new Error(`Incorrect Handle ${index}: (expected) ${expected} != ${current} (received)`);
|
|
2096
2522
|
}
|
|
@@ -2129,10 +2555,10 @@ const createRelayerEncryptedInput = (aclContractAddress, verifyingContractAddres
|
|
|
2129
2555
|
throw Error('Coprocessor signers threshold is not reached');
|
|
2130
2556
|
}
|
|
2131
2557
|
// inputProof is len(list_handles) + numCoprocessorSigners + list_handles + signatureCoprocessorSigners (1+1+NUM_HANDLES*32+65*numSigners)
|
|
2132
|
-
let inputProof =
|
|
2558
|
+
let inputProof = numberToHexNo0x(handles.length);
|
|
2133
2559
|
const numSigners = signatures.length;
|
|
2134
|
-
inputProof +=
|
|
2135
|
-
const listHandlesStr = handles.map((i) =>
|
|
2560
|
+
inputProof += numberToHexNo0x(numSigners);
|
|
2561
|
+
const listHandlesStr = handles.map((i) => bytesToHexNo0x(i));
|
|
2136
2562
|
listHandlesStr.map((handle) => (inputProof += handle));
|
|
2137
2563
|
signatures.map((signature) => (inputProof += signature.slice(2))); // removes the '0x' prefix from the `signature` string
|
|
2138
2564
|
// Append the extra data to the input proof
|
|
@@ -2185,7 +2611,7 @@ function abiEncodeClearValues(clearValues) {
|
|
|
2185
2611
|
const abiValues = [];
|
|
2186
2612
|
for (let i = 0; i < handlesBytes32Hex.length; ++i) {
|
|
2187
2613
|
const handle = handlesBytes32Hex[i];
|
|
2188
|
-
const handleType = FhevmHandle.
|
|
2614
|
+
const handleType = FhevmHandle.parse(handle).fheTypeId;
|
|
2189
2615
|
let clearTextValue = clearValues[handle];
|
|
2190
2616
|
if (typeof clearTextValue === 'boolean') {
|
|
2191
2617
|
clearTextValue = clearTextValue ? '0x01' : '0x00';
|
|
@@ -2248,24 +2674,23 @@ function buildDecryptionProof(kmsSignatures, extraData) {
|
|
|
2248
2674
|
return decryptionProof;
|
|
2249
2675
|
}
|
|
2250
2676
|
function deserializeClearValues(handles, decryptedResult) {
|
|
2251
|
-
let
|
|
2677
|
+
let fheTypeIdList = [];
|
|
2252
2678
|
for (const handle of handles) {
|
|
2253
|
-
const typeDiscriminant = FhevmHandle.
|
|
2254
|
-
|
|
2255
|
-
typesList.push(typeDiscriminant);
|
|
2679
|
+
const typeDiscriminant = FhevmHandle.parse(handle).fheTypeId;
|
|
2680
|
+
fheTypeIdList.push(typeDiscriminant);
|
|
2256
2681
|
}
|
|
2257
2682
|
const restoredEncoded = '0x' +
|
|
2258
2683
|
'00'.repeat(32) + // dummy requestID (ignored)
|
|
2259
2684
|
decryptedResult.slice(2) +
|
|
2260
2685
|
'00'.repeat(32); // dummy empty bytes[] length (ignored)
|
|
2261
|
-
const abiTypes =
|
|
2262
|
-
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
|
|
2263
2688
|
return abiType;
|
|
2264
2689
|
});
|
|
2265
2690
|
const coder = new ethers.AbiCoder();
|
|
2266
2691
|
const decoded = coder.decode(['uint256', ...abiTypes, 'bytes[]'], restoredEncoded);
|
|
2267
2692
|
// strip dummy first/last element
|
|
2268
|
-
const rawValues = decoded.slice(1, 1 +
|
|
2693
|
+
const rawValues = decoded.slice(1, 1 + fheTypeIdList.length);
|
|
2269
2694
|
const results = {};
|
|
2270
2695
|
handles.forEach((handle, idx) => (results[handle] = rawValues[idx]));
|
|
2271
2696
|
return results;
|
|
@@ -2273,12 +2698,13 @@ function deserializeClearValues(handles, decryptedResult) {
|
|
|
2273
2698
|
const publicDecryptRequest = (kmsSigners, thresholdSigners, gatewayChainId, verifyingContractAddress, aclContractAddress, relayerProvider, provider, defaultOptions) => async (_handles, options) => {
|
|
2274
2699
|
const extraData = '0x00';
|
|
2275
2700
|
const acl = new ethers.ethers.Contract(aclContractAddress, aclABI, provider);
|
|
2701
|
+
// This will be replaced by new sanitize classes
|
|
2276
2702
|
let handles;
|
|
2277
2703
|
try {
|
|
2278
2704
|
handles = await Promise.all(_handles.map(async (_handle) => {
|
|
2279
2705
|
const handle = typeof _handle === 'string'
|
|
2280
|
-
?
|
|
2281
|
-
:
|
|
2706
|
+
? bytesToHex(hexToBytes(_handle))
|
|
2707
|
+
: bytesToHex(_handle);
|
|
2282
2708
|
const isAllowedForDecryption = await acl.isAllowedForDecryption(handle);
|
|
2283
2709
|
if (!isAllowedForDecryption) {
|
|
2284
2710
|
throw new Error(`Handle ${handle} is not allowed for public decryption!`);
|
|
@@ -2436,8 +2862,8 @@ const createEIP712 = (verifyingContract, contractsChainId) => (publicKey, contra
|
|
|
2436
2862
|
const generateKeypair = () => {
|
|
2437
2863
|
const keypair = TKMS.ml_kem_pke_keygen();
|
|
2438
2864
|
return {
|
|
2439
|
-
publicKey:
|
|
2440
|
-
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)),
|
|
2441
2867
|
};
|
|
2442
2868
|
};
|
|
2443
2869
|
|
|
@@ -3101,7 +3527,28 @@ function assertIsRelayerV2GetResponseQueued(value, name) {
|
|
|
3101
3527
|
assertRecordStringProperty(value, 'requestId', name);
|
|
3102
3528
|
}
|
|
3103
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
|
+
|
|
3104
3550
|
class RelayerV2AsyncRequest {
|
|
3551
|
+
_fetchMethod;
|
|
3105
3552
|
_jobId;
|
|
3106
3553
|
_jobIdTimestamp;
|
|
3107
3554
|
_state;
|
|
@@ -3116,17 +3563,18 @@ class RelayerV2AsyncRequest {
|
|
|
3116
3563
|
_retryAfterTimeoutID;
|
|
3117
3564
|
_url;
|
|
3118
3565
|
_payload;
|
|
3119
|
-
|
|
3566
|
+
_fhevmAuth;
|
|
3120
3567
|
_retryAfterTimeoutPromiseFuncReject;
|
|
3121
3568
|
_onProgress;
|
|
3122
|
-
|
|
3569
|
+
_requestMaxDurationInMs;
|
|
3123
3570
|
_requestStartTimestamp;
|
|
3124
3571
|
_requestGlobalTimeoutID;
|
|
3125
3572
|
_throwErrorIfNoRetryAfter;
|
|
3126
|
-
static
|
|
3127
|
-
static
|
|
3128
|
-
static
|
|
3129
|
-
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;
|
|
3130
3578
|
constructor(params) {
|
|
3131
3579
|
if (params.relayerOperation !== 'INPUT_PROOF' &&
|
|
3132
3580
|
params.relayerOperation !== 'PUBLIC_DECRYPT' &&
|
|
@@ -3143,14 +3591,14 @@ class RelayerV2AsyncRequest {
|
|
|
3143
3591
|
this._internalAbortController = new AbortController();
|
|
3144
3592
|
this._internalAbortSignal = this._internalAbortController.signal;
|
|
3145
3593
|
this._internalAbortSignal.addEventListener('abort', this._handleInternalSignalAbort);
|
|
3146
|
-
this._externalAbortSignal = params.signal;
|
|
3594
|
+
this._externalAbortSignal = params.options?.signal;
|
|
3147
3595
|
if (this._externalAbortSignal) {
|
|
3148
3596
|
this._externalAbortSignal.addEventListener('abort', this._handleExternalSignalAbort);
|
|
3149
3597
|
}
|
|
3150
3598
|
this._url = params.url;
|
|
3151
3599
|
this._payload = params.payload;
|
|
3152
|
-
this.
|
|
3153
|
-
this._onProgress = params.onProgress;
|
|
3600
|
+
this._fhevmAuth = params.options?.auth;
|
|
3601
|
+
this._onProgress = params.options?.onProgress;
|
|
3154
3602
|
this._state = {
|
|
3155
3603
|
aborted: false,
|
|
3156
3604
|
canceled: false,
|
|
@@ -3159,6 +3607,7 @@ class RelayerV2AsyncRequest {
|
|
|
3159
3607
|
running: false,
|
|
3160
3608
|
succeeded: false,
|
|
3161
3609
|
terminated: false,
|
|
3610
|
+
timeout: false,
|
|
3162
3611
|
};
|
|
3163
3612
|
this._retryCount = 0;
|
|
3164
3613
|
this._retryAfterTimeoutID = undefined;
|
|
@@ -3166,9 +3615,9 @@ class RelayerV2AsyncRequest {
|
|
|
3166
3615
|
this._terminateReason = undefined;
|
|
3167
3616
|
this._publicAPINoReentrancy = false;
|
|
3168
3617
|
this._throwErrorIfNoRetryAfter = params.throwErrorIfNoRetryAfter ?? false;
|
|
3169
|
-
this.
|
|
3170
|
-
params.
|
|
3171
|
-
RelayerV2AsyncRequest.
|
|
3618
|
+
this._requestMaxDurationInMs =
|
|
3619
|
+
params.options?.timeout ??
|
|
3620
|
+
RelayerV2AsyncRequest.DEFAULT_GLOBAL_REQUEST_TIMEOUT_MS;
|
|
3172
3621
|
}
|
|
3173
3622
|
//////////////////////////////////////////////////////////////////////////////
|
|
3174
3623
|
// Public API: run
|
|
@@ -3210,6 +3659,12 @@ class RelayerV2AsyncRequest {
|
|
|
3210
3659
|
state: { ...this._state },
|
|
3211
3660
|
});
|
|
3212
3661
|
}
|
|
3662
|
+
if (this._state.timeout) {
|
|
3663
|
+
throw new RelayerV2StateError({
|
|
3664
|
+
message: `Relayer.run() failed. Request already timeout.`,
|
|
3665
|
+
state: { ...this._state },
|
|
3666
|
+
});
|
|
3667
|
+
}
|
|
3213
3668
|
if (this._externalAbortSignal?.aborted === true) {
|
|
3214
3669
|
throw new RelayerV2StateError({
|
|
3215
3670
|
message: `Relayer.run() failed. External AbortSignal already aborted (reason:${this._externalAbortSignal?.reason}).`,
|
|
@@ -3230,7 +3685,7 @@ class RelayerV2AsyncRequest {
|
|
|
3230
3685
|
}
|
|
3231
3686
|
this._state.running = true;
|
|
3232
3687
|
this._requestStartTimestamp = Date.now();
|
|
3233
|
-
this._setGlobalRequestTimeout(this.
|
|
3688
|
+
this._setGlobalRequestTimeout(this._requestMaxDurationInMs);
|
|
3234
3689
|
try {
|
|
3235
3690
|
const json = await this._runPostLoop();
|
|
3236
3691
|
this._state.succeeded = true;
|
|
@@ -3301,6 +3756,12 @@ class RelayerV2AsyncRequest {
|
|
|
3301
3756
|
get failed() {
|
|
3302
3757
|
return this._state.failed;
|
|
3303
3758
|
}
|
|
3759
|
+
get aborted() {
|
|
3760
|
+
return this._state.aborted;
|
|
3761
|
+
}
|
|
3762
|
+
get timeout() {
|
|
3763
|
+
return this._state.timeout;
|
|
3764
|
+
}
|
|
3304
3765
|
get succeeded() {
|
|
3305
3766
|
return this._state.succeeded;
|
|
3306
3767
|
}
|
|
@@ -3321,6 +3782,8 @@ class RelayerV2AsyncRequest {
|
|
|
3321
3782
|
//////////////////////////////////////////////////////////////////////////////
|
|
3322
3783
|
// POST : 202 | 400 | 429 | 500 | 503
|
|
3323
3784
|
async _runPostLoop() {
|
|
3785
|
+
this._assert(this._fetchMethod === undefined, 'this._fetchMethod === undefined');
|
|
3786
|
+
this._fetchMethod = 'POST';
|
|
3324
3787
|
// No infinite loop!
|
|
3325
3788
|
let i = 0;
|
|
3326
3789
|
while (i < RelayerV2AsyncRequest.MAX_POST_RETRY) {
|
|
@@ -3356,9 +3819,7 @@ class RelayerV2AsyncRequest {
|
|
|
3356
3819
|
bodyJson: safeJSONstringify(bodyJson),
|
|
3357
3820
|
});
|
|
3358
3821
|
}
|
|
3359
|
-
|
|
3360
|
-
if (retry_after_sec < 1)
|
|
3361
|
-
retry_after_sec = 1;
|
|
3822
|
+
const retryAfterMs = this._getRetryAfterHeaderValueInMs(response);
|
|
3362
3823
|
// Debug: will throw an assert failed error if jobId has already been set
|
|
3363
3824
|
this._setJobIdOnce(bodyJson.result.jobId);
|
|
3364
3825
|
// Async onProgress callback
|
|
@@ -3371,11 +3832,10 @@ class RelayerV2AsyncRequest {
|
|
|
3371
3832
|
jobId: this.jobId,
|
|
3372
3833
|
operation: this._relayerOperation,
|
|
3373
3834
|
retryCount: this._retryCount,
|
|
3374
|
-
|
|
3835
|
+
retryAfterMs,
|
|
3375
3836
|
elapsed,
|
|
3376
3837
|
});
|
|
3377
|
-
|
|
3378
|
-
await this._setRetryAfterTimeout(retry_after_sec * 1000);
|
|
3838
|
+
await this._setRetryAfterTimeout(retryAfterMs);
|
|
3379
3839
|
const json = await this._runGetLoop();
|
|
3380
3840
|
return json;
|
|
3381
3841
|
}
|
|
@@ -3421,22 +3881,20 @@ class RelayerV2AsyncRequest {
|
|
|
3421
3881
|
bodyJson: safeJSONstringify(bodyJson),
|
|
3422
3882
|
});
|
|
3423
3883
|
}
|
|
3424
|
-
|
|
3425
|
-
if (retry_after_sec < 1)
|
|
3426
|
-
retry_after_sec = 1;
|
|
3884
|
+
const retryAfterMs = this._getRetryAfterHeaderValueInMs(response);
|
|
3427
3885
|
// Async onProgress callback
|
|
3428
3886
|
this._postAsyncOnProgressCallback({
|
|
3429
3887
|
type: 'ratelimited',
|
|
3430
3888
|
url: this._url,
|
|
3431
3889
|
method: 'POST',
|
|
3432
3890
|
status: responseStatus,
|
|
3433
|
-
|
|
3891
|
+
retryAfterMs,
|
|
3434
3892
|
retryCount: this._retryCount,
|
|
3435
3893
|
elapsed,
|
|
3436
|
-
|
|
3894
|
+
relayerApiError: bodyJson.error,
|
|
3437
3895
|
});
|
|
3438
3896
|
// Wait if needed (minimum 1s)
|
|
3439
|
-
await this._setRetryAfterTimeout(
|
|
3897
|
+
await this._setRetryAfterTimeout(retryAfterMs);
|
|
3440
3898
|
continue;
|
|
3441
3899
|
}
|
|
3442
3900
|
// RelayerV2ResponseFailed
|
|
@@ -3515,8 +3973,10 @@ class RelayerV2AsyncRequest {
|
|
|
3515
3973
|
// GET: 200 | 202 | 404 | 500 | 503 | 504
|
|
3516
3974
|
// GET is not rate-limited, therefore there is not 429 error
|
|
3517
3975
|
async _runGetLoop() {
|
|
3976
|
+
this._assert(this._fetchMethod === 'POST', "this._fetchMethod === 'POST'");
|
|
3518
3977
|
this._assert(this._jobId !== undefined, 'this._jobId !== undefined');
|
|
3519
3978
|
this._assert(this._jobIdTimestamp !== undefined, 'this._jobIdTimestamp !== undefined');
|
|
3979
|
+
this._fetchMethod = 'GET';
|
|
3520
3980
|
let i = 0;
|
|
3521
3981
|
while (i < RelayerV2AsyncRequest.MAX_GET_RETRY) {
|
|
3522
3982
|
++i;
|
|
@@ -3626,9 +4086,7 @@ class RelayerV2AsyncRequest {
|
|
|
3626
4086
|
bodyJson: safeJSONstringify(bodyJson),
|
|
3627
4087
|
});
|
|
3628
4088
|
}
|
|
3629
|
-
|
|
3630
|
-
if (retry_after_sec < 1)
|
|
3631
|
-
retry_after_sec = 1;
|
|
4089
|
+
const retryAfterMs = this._getRetryAfterHeaderValueInMs(response);
|
|
3632
4090
|
// Async onProgress callback
|
|
3633
4091
|
this._postAsyncOnProgressCallback({
|
|
3634
4092
|
type: 'queued',
|
|
@@ -3638,12 +4096,12 @@ class RelayerV2AsyncRequest {
|
|
|
3638
4096
|
requestId: bodyJson.requestId,
|
|
3639
4097
|
operation: this._relayerOperation,
|
|
3640
4098
|
jobId: this.jobId,
|
|
3641
|
-
|
|
4099
|
+
retryAfterMs,
|
|
3642
4100
|
retryCount: this._retryCount,
|
|
3643
4101
|
elapsed,
|
|
3644
4102
|
});
|
|
3645
4103
|
// Wait if needed (minimum 1s)
|
|
3646
|
-
await this._setRetryAfterTimeout(
|
|
4104
|
+
await this._setRetryAfterTimeout(retryAfterMs);
|
|
3647
4105
|
continue;
|
|
3648
4106
|
}
|
|
3649
4107
|
case 400: {
|
|
@@ -3795,17 +4253,20 @@ class RelayerV2AsyncRequest {
|
|
|
3795
4253
|
return bodyJson;
|
|
3796
4254
|
}
|
|
3797
4255
|
//////////////////////////////////////////////////////////////////////////////
|
|
3798
|
-
|
|
4256
|
+
_getRetryAfterHeaderValueInMs(response) {
|
|
3799
4257
|
if (!response.headers.has('Retry-After')) {
|
|
3800
4258
|
if (this._throwErrorIfNoRetryAfter) {
|
|
3801
4259
|
throw new Error(`Missing 'Retry-After' header key`);
|
|
3802
4260
|
}
|
|
3803
|
-
return RelayerV2AsyncRequest.
|
|
4261
|
+
return RelayerV2AsyncRequest.DEFAULT_RETRY_AFTER_MS;
|
|
3804
4262
|
}
|
|
3805
4263
|
try {
|
|
3806
4264
|
const n = Number.parseInt(response.headers.get('Retry-After'));
|
|
3807
4265
|
if (isUint(n)) {
|
|
3808
|
-
|
|
4266
|
+
const ms = n * 1000;
|
|
4267
|
+
return ms < RelayerV2AsyncRequest.MINIMUM_RETRY_AFTER_MS
|
|
4268
|
+
? RelayerV2AsyncRequest.MINIMUM_RETRY_AFTER_MS
|
|
4269
|
+
: ms;
|
|
3809
4270
|
}
|
|
3810
4271
|
}
|
|
3811
4272
|
catch {
|
|
@@ -3814,7 +4275,7 @@ class RelayerV2AsyncRequest {
|
|
|
3814
4275
|
if (this._throwErrorIfNoRetryAfter) {
|
|
3815
4276
|
throw new Error(`Invalid 'Retry-After' header key`);
|
|
3816
4277
|
}
|
|
3817
|
-
return RelayerV2AsyncRequest.
|
|
4278
|
+
return RelayerV2AsyncRequest.DEFAULT_RETRY_AFTER_MS;
|
|
3818
4279
|
}
|
|
3819
4280
|
//////////////////////////////////////////////////////////////////////////////
|
|
3820
4281
|
// JobId
|
|
@@ -3853,7 +4314,7 @@ class RelayerV2AsyncRequest {
|
|
|
3853
4314
|
this._assert(this._jobId === undefined, 'this._jobId === undefined');
|
|
3854
4315
|
this._assert(!this._state.terminated, '!this._state.terminated');
|
|
3855
4316
|
this._assert(!this._state.fetching, '!this._state.fetching');
|
|
3856
|
-
this._trace('_fetchPost',
|
|
4317
|
+
this._trace('_fetchPost', this._url);
|
|
3857
4318
|
const init = setAuth({
|
|
3858
4319
|
method: 'POST',
|
|
3859
4320
|
headers: {
|
|
@@ -3865,7 +4326,7 @@ class RelayerV2AsyncRequest {
|
|
|
3865
4326
|
...(this._internalAbortSignal
|
|
3866
4327
|
? { signal: this._internalAbortSignal }
|
|
3867
4328
|
: {}),
|
|
3868
|
-
}, this.
|
|
4329
|
+
}, this._fhevmAuth);
|
|
3869
4330
|
this._state.fetching = true;
|
|
3870
4331
|
let response;
|
|
3871
4332
|
try {
|
|
@@ -3992,7 +4453,18 @@ class RelayerV2AsyncRequest {
|
|
|
3992
4453
|
if (signal.reason !== 'cancel') {
|
|
3993
4454
|
this._assert(!this._state.canceled, '!this._state.canceled');
|
|
3994
4455
|
}
|
|
3995
|
-
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
|
+
}));
|
|
3996
4468
|
};
|
|
3997
4469
|
//////////////////////////////////////////////////////////////////////////////
|
|
3998
4470
|
// Terminate
|
|
@@ -4016,7 +4488,7 @@ class RelayerV2AsyncRequest {
|
|
|
4016
4488
|
this._terminateReason = reason;
|
|
4017
4489
|
this._terminateError = error;
|
|
4018
4490
|
this._state.terminated = true;
|
|
4019
|
-
this._tryClearRetryAfterTimeout();
|
|
4491
|
+
this._tryClearRetryAfterTimeout(error);
|
|
4020
4492
|
this._tryClearGlobalRequestTimeout();
|
|
4021
4493
|
const is = this._internalAbortSignal;
|
|
4022
4494
|
const es = this._externalAbortSignal;
|
|
@@ -4038,7 +4510,7 @@ class RelayerV2AsyncRequest {
|
|
|
4038
4510
|
// Debug
|
|
4039
4511
|
this._assert(!this._state.terminated, '!this._state.terminated');
|
|
4040
4512
|
this._assert(this._retryAfterTimeoutID === undefined, 'this._retryAfterTimeoutID === undefined');
|
|
4041
|
-
this._assert(delayMs >=
|
|
4513
|
+
this._assert(delayMs >= RelayerV2AsyncRequest.MINIMUM_RETRY_AFTER_MS, `delayMs >= ${RelayerV2AsyncRequest.MINIMUM_RETRY_AFTER_MS}`);
|
|
4042
4514
|
this._trace('_setRetryAfterTimeout', `delayMs=${delayMs}`);
|
|
4043
4515
|
if (this._retryAfterTimeoutID !== undefined) {
|
|
4044
4516
|
return Promise.reject(new Error(`retry-after already running.`));
|
|
@@ -4058,7 +4530,7 @@ class RelayerV2AsyncRequest {
|
|
|
4058
4530
|
return p;
|
|
4059
4531
|
}
|
|
4060
4532
|
//////////////////////////////////////////////////////////////////////////////
|
|
4061
|
-
_tryClearRetryAfterTimeout() {
|
|
4533
|
+
_tryClearRetryAfterTimeout(error) {
|
|
4062
4534
|
if (this._retryAfterTimeoutID === undefined) {
|
|
4063
4535
|
// Debug
|
|
4064
4536
|
this._assert(this._retryAfterTimeoutPromiseFuncReject === undefined, 'this._retryAfterTimeoutPromiseFuncReject === undefined');
|
|
@@ -4069,7 +4541,8 @@ class RelayerV2AsyncRequest {
|
|
|
4069
4541
|
this._retryAfterTimeoutID = undefined;
|
|
4070
4542
|
this._retryAfterTimeoutPromiseFuncReject = undefined;
|
|
4071
4543
|
clearTimeout(tid);
|
|
4072
|
-
reject
|
|
4544
|
+
// Calling reject will
|
|
4545
|
+
reject(error ?? new Error('_tryClearRetryAfterTimeout'));
|
|
4073
4546
|
}
|
|
4074
4547
|
//////////////////////////////////////////////////////////////////////////////
|
|
4075
4548
|
// Global Request Timeout
|
|
@@ -4084,7 +4557,24 @@ class RelayerV2AsyncRequest {
|
|
|
4084
4557
|
this._requestGlobalTimeoutID = setTimeout(callback, delayMs);
|
|
4085
4558
|
}
|
|
4086
4559
|
_handleGlobalRequestTimeout() {
|
|
4087
|
-
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
|
+
}));
|
|
4088
4578
|
}
|
|
4089
4579
|
_tryClearGlobalRequestTimeout() {
|
|
4090
4580
|
if (this._requestGlobalTimeoutID === undefined) {
|
|
@@ -4292,37 +4782,34 @@ class RelayerV2Provider extends AbstractRelayerProvider {
|
|
|
4292
4782
|
const response = await this.fetchGetKeyUrlV2();
|
|
4293
4783
|
return toRelayerV1KeyUrlResponse(response);
|
|
4294
4784
|
}
|
|
4295
|
-
async fetchPostInputProof(payload,
|
|
4785
|
+
async fetchPostInputProof(payload, options) {
|
|
4296
4786
|
const request = new RelayerV2AsyncRequest({
|
|
4297
4787
|
relayerOperation: 'INPUT_PROOF',
|
|
4298
4788
|
url: this.inputProof,
|
|
4299
4789
|
payload,
|
|
4300
|
-
|
|
4301
|
-
...fetchOptions,
|
|
4790
|
+
options,
|
|
4302
4791
|
});
|
|
4303
4792
|
const result = (await request.run());
|
|
4304
4793
|
assertIsRelayerInputProofResult(result, 'fetchPostInputProof()');
|
|
4305
4794
|
return result;
|
|
4306
4795
|
}
|
|
4307
|
-
async fetchPostPublicDecrypt(payload,
|
|
4796
|
+
async fetchPostPublicDecrypt(payload, options) {
|
|
4308
4797
|
const request = new RelayerV2AsyncRequest({
|
|
4309
4798
|
relayerOperation: 'PUBLIC_DECRYPT',
|
|
4310
4799
|
url: this.publicDecrypt,
|
|
4311
4800
|
payload,
|
|
4312
|
-
|
|
4313
|
-
...fetchOptions,
|
|
4801
|
+
options,
|
|
4314
4802
|
});
|
|
4315
4803
|
const result = await request.run();
|
|
4316
4804
|
assertIsRelayerPublicDecryptResult(result, 'fetchPostPublicDecrypt()');
|
|
4317
4805
|
return result;
|
|
4318
4806
|
}
|
|
4319
|
-
async fetchPostUserDecrypt(payload,
|
|
4807
|
+
async fetchPostUserDecrypt(payload, options) {
|
|
4320
4808
|
const request = new RelayerV2AsyncRequest({
|
|
4321
4809
|
relayerOperation: 'USER_DECRYPT',
|
|
4322
4810
|
url: this.userDecrypt,
|
|
4323
4811
|
payload,
|
|
4324
|
-
|
|
4325
|
-
...fetchOptions,
|
|
4812
|
+
options,
|
|
4326
4813
|
});
|
|
4327
4814
|
const result = (await request.run());
|
|
4328
4815
|
assertIsRelayerUserDecryptResult(result.result, 'fetchPostUserDecrypt()');
|
|
@@ -4330,6 +4817,16 @@ class RelayerV2Provider extends AbstractRelayerProvider {
|
|
|
4330
4817
|
}
|
|
4331
4818
|
}
|
|
4332
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
|
+
|
|
4333
4830
|
class AbstractRelayerFhevm {
|
|
4334
4831
|
}
|
|
4335
4832
|
|
|
@@ -4344,6 +4841,15 @@ class TFHECrs {
|
|
|
4344
4841
|
this._bits = params.bits;
|
|
4345
4842
|
this._srcUrl = params.srcUrl;
|
|
4346
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
|
+
}
|
|
4347
4853
|
/*
|
|
4348
4854
|
{
|
|
4349
4855
|
id: string,
|
|
@@ -4446,19 +4952,57 @@ class TFHECrs {
|
|
|
4446
4952
|
return TFHECrs._fromUrl(params);
|
|
4447
4953
|
}
|
|
4448
4954
|
else {
|
|
4449
|
-
throw new
|
|
4955
|
+
throw new TFHECrsError({
|
|
4956
|
+
message: 'Invalid public key (deserialization failed)',
|
|
4957
|
+
});
|
|
4450
4958
|
}
|
|
4451
4959
|
}
|
|
4960
|
+
/*
|
|
4961
|
+
{
|
|
4962
|
+
id: string;
|
|
4963
|
+
data: Uint8Array;
|
|
4964
|
+
bits: number;
|
|
4965
|
+
srcUrl?: string;
|
|
4966
|
+
}
|
|
4967
|
+
*/
|
|
4452
4968
|
static fromBytes(params) {
|
|
4453
4969
|
try {
|
|
4454
4970
|
TFHECrs.assertKeyBytesType(params, 'arg');
|
|
4455
4971
|
return TFHECrs._fromBytes(params);
|
|
4456
4972
|
}
|
|
4457
4973
|
catch (e) {
|
|
4458
|
-
throw new
|
|
4974
|
+
throw new TFHECrsError({
|
|
4975
|
+
message: 'Invalid public key (deserialization failed)',
|
|
4976
|
+
cause: e,
|
|
4977
|
+
});
|
|
4978
|
+
}
|
|
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)',
|
|
4459
4997
|
cause: e,
|
|
4460
4998
|
});
|
|
4461
4999
|
}
|
|
5000
|
+
return TFHECrs.fromBytes({
|
|
5001
|
+
id: params?.id,
|
|
5002
|
+
bits: params?.bits,
|
|
5003
|
+
srcUrl: params?.srcUrl,
|
|
5004
|
+
data,
|
|
5005
|
+
});
|
|
4462
5006
|
}
|
|
4463
5007
|
static _fromBytes(params) {
|
|
4464
5008
|
const _params = {
|
|
@@ -4475,7 +5019,50 @@ class TFHECrs {
|
|
|
4475
5019
|
return TFHECrs._fromPublicParamsBytes(params);
|
|
4476
5020
|
}
|
|
4477
5021
|
catch (e) {
|
|
4478
|
-
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)',
|
|
4479
5066
|
cause: e,
|
|
4480
5067
|
});
|
|
4481
5068
|
}
|
|
@@ -4493,7 +5080,8 @@ class TFHECrs {
|
|
|
4493
5080
|
return TFHECrs._fromUrl(params);
|
|
4494
5081
|
}
|
|
4495
5082
|
catch (e) {
|
|
4496
|
-
throw new
|
|
5083
|
+
throw new TFHECrsError({
|
|
5084
|
+
message: 'Impossible to fetch public key: wrong relayer url.',
|
|
4497
5085
|
cause: e,
|
|
4498
5086
|
});
|
|
4499
5087
|
}
|
|
@@ -4524,6 +5112,22 @@ class TFHECrs {
|
|
|
4524
5112
|
...(this._srcUrl ? { srcUrl: this._srcUrl } : {}),
|
|
4525
5113
|
};
|
|
4526
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
|
+
}
|
|
4527
5131
|
/*
|
|
4528
5132
|
{
|
|
4529
5133
|
2048: {
|
|
@@ -4532,9 +5136,11 @@ class TFHECrs {
|
|
|
4532
5136
|
}
|
|
4533
5137
|
}
|
|
4534
5138
|
*/
|
|
4535
|
-
|
|
5139
|
+
toPublicParams2048Wasm() {
|
|
4536
5140
|
if (this._bits !== 2048) {
|
|
4537
|
-
throw new
|
|
5141
|
+
throw new TFHECrsError({
|
|
5142
|
+
message: `Unsupported PublicParams bits format '2048'`,
|
|
5143
|
+
});
|
|
4538
5144
|
}
|
|
4539
5145
|
const pp = {
|
|
4540
5146
|
2048: {
|
|
@@ -4552,9 +5158,11 @@ class TFHECrs {
|
|
|
4552
5158
|
}
|
|
4553
5159
|
}
|
|
4554
5160
|
*/
|
|
4555
|
-
|
|
5161
|
+
toPublicParams2048Bytes() {
|
|
4556
5162
|
if (this._bits !== 2048) {
|
|
4557
|
-
throw new
|
|
5163
|
+
throw new TFHECrsError({
|
|
5164
|
+
message: `Unsupported PublicParams bits format '2048'`,
|
|
5165
|
+
});
|
|
4558
5166
|
}
|
|
4559
5167
|
const pp = {
|
|
4560
5168
|
2048: {
|
|
@@ -4564,6 +5172,64 @@ class TFHECrs {
|
|
|
4564
5172
|
};
|
|
4565
5173
|
return pp;
|
|
4566
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
|
+
}
|
|
4567
5233
|
}
|
|
4568
5234
|
|
|
4569
5235
|
class TFHEPublicKey {
|
|
@@ -4575,6 +5241,12 @@ class TFHEPublicKey {
|
|
|
4575
5241
|
this._tfheCompactPublicKey = params.tfheCompactPublicKey;
|
|
4576
5242
|
this._srcUrl = params.srcUrl;
|
|
4577
5243
|
}
|
|
5244
|
+
get id() {
|
|
5245
|
+
return this._id;
|
|
5246
|
+
}
|
|
5247
|
+
get srcUrl() {
|
|
5248
|
+
return this._srcUrl;
|
|
5249
|
+
}
|
|
4578
5250
|
/*
|
|
4579
5251
|
{
|
|
4580
5252
|
id: string,
|
|
@@ -4659,6 +5331,30 @@ class TFHEPublicKey {
|
|
|
4659
5331
|
});
|
|
4660
5332
|
}
|
|
4661
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
|
+
}
|
|
4662
5358
|
/*
|
|
4663
5359
|
{
|
|
4664
5360
|
id: string,
|
|
@@ -4719,6 +5415,20 @@ class TFHEPublicKey {
|
|
|
4719
5415
|
...(this._srcUrl ? { srcUrl: this._srcUrl } : {}),
|
|
4720
5416
|
};
|
|
4721
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
|
+
}
|
|
4722
5432
|
/*
|
|
4723
5433
|
{
|
|
4724
5434
|
publicKey: TFHE.TfheCompactPublicKey
|
|
@@ -4743,6 +5453,75 @@ class TFHEPublicKey {
|
|
|
4743
5453
|
publicKeyId: this._id,
|
|
4744
5454
|
};
|
|
4745
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
|
+
}
|
|
4746
5525
|
}
|
|
4747
5526
|
|
|
4748
5527
|
//const __KEY_URL_CACHE__: Record<string, RelayerV2PublicKey> = {};
|
|
@@ -4818,7 +5597,7 @@ class RelayerV2PublicKey {
|
|
|
4818
5597
|
toBytes() {
|
|
4819
5598
|
return {
|
|
4820
5599
|
publicKey: this._publicKey.toBytes(),
|
|
4821
|
-
publicParams: this._crs2048.
|
|
5600
|
+
publicParams: this._crs2048.toPublicParams2048Bytes(),
|
|
4822
5601
|
};
|
|
4823
5602
|
}
|
|
4824
5603
|
}
|
|
@@ -4852,23 +5631,46 @@ class RelayerV2Fhevm extends AbstractRelayerFhevm {
|
|
|
4852
5631
|
get relayerProvider() {
|
|
4853
5632
|
return this._relayerProvider;
|
|
4854
5633
|
}
|
|
5634
|
+
getPublicKeyInfo() {
|
|
5635
|
+
return {
|
|
5636
|
+
id: this._relayerPublicKey.getTFHEPublicKey().id,
|
|
5637
|
+
srcUrl: this._relayerPublicKey.getTFHEPublicKey().srcUrl,
|
|
5638
|
+
};
|
|
5639
|
+
}
|
|
4855
5640
|
getPublicKeyBytes() {
|
|
4856
5641
|
return this._relayerPublicKey.getTFHEPublicKey().toPublicKeyBytes();
|
|
4857
5642
|
}
|
|
4858
5643
|
getPublicKeyWasm() {
|
|
4859
5644
|
return this._relayerPublicKey.getTFHEPublicKey().toPublicKeyWasm();
|
|
4860
5645
|
}
|
|
4861
|
-
|
|
5646
|
+
getPublicParamsBytesForBits(bits) {
|
|
5647
|
+
if (bits === undefined) {
|
|
5648
|
+
throw new TFHECrsError({ message: `Missing PublicParams bits format` });
|
|
5649
|
+
}
|
|
4862
5650
|
if (bits !== 2048) {
|
|
4863
|
-
throw new
|
|
5651
|
+
throw new TFHECrsError({
|
|
5652
|
+
message: `Unsupported PublicParams bits format '${bits}'`,
|
|
5653
|
+
});
|
|
4864
5654
|
}
|
|
4865
|
-
return this._relayerPublicKey.getTFHECrs().
|
|
5655
|
+
return this._relayerPublicKey.getTFHECrs().toPublicParams2048Bytes()['2048'];
|
|
4866
5656
|
}
|
|
4867
|
-
|
|
5657
|
+
getPublicParamsWasmForBits(bits) {
|
|
5658
|
+
if (bits === undefined) {
|
|
5659
|
+
throw new TFHECrsError({ message: `Missing PublicParams bits format` });
|
|
5660
|
+
}
|
|
4868
5661
|
if (bits !== 2048) {
|
|
4869
|
-
throw new
|
|
5662
|
+
throw new TFHECrsError({
|
|
5663
|
+
message: `Unsupported PublicParams bits format '${bits}'`,
|
|
5664
|
+
});
|
|
4870
5665
|
}
|
|
4871
|
-
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
|
+
};
|
|
4872
5674
|
}
|
|
4873
5675
|
}
|
|
4874
5676
|
|
|
@@ -4907,24 +5709,42 @@ class RelayerV1Fhevm extends AbstractRelayerFhevm {
|
|
|
4907
5709
|
publicKeyId: this._publicKeyData.publicKeyId,
|
|
4908
5710
|
};
|
|
4909
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
|
+
}
|
|
4910
5723
|
getPublicKeyWasm() {
|
|
4911
5724
|
return {
|
|
4912
5725
|
publicKey: this._publicKeyData.publicKey,
|
|
4913
5726
|
publicKeyId: this._publicKeyData.publicKeyId,
|
|
4914
5727
|
};
|
|
4915
5728
|
}
|
|
4916
|
-
|
|
5729
|
+
getPublicParamsBytesForBits(bits) {
|
|
5730
|
+
if (bits === undefined) {
|
|
5731
|
+
throw new Error(`Missing PublicParams bits format`);
|
|
5732
|
+
}
|
|
4917
5733
|
if (bits !== 2048) {
|
|
4918
|
-
throw new Error(`Unsupported PublicParams bits format ${bits}`);
|
|
5734
|
+
throw new Error(`Unsupported PublicParams bits format '${bits}'`);
|
|
4919
5735
|
}
|
|
4920
|
-
|
|
5736
|
+
const res = {
|
|
4921
5737
|
publicParams: this._publicParamsData['2048'].publicParams.safe_serialize(SERIALIZED_SIZE_LIMIT_CRS),
|
|
4922
5738
|
publicParamsId: this._publicParamsData['2048'].publicParamsId,
|
|
4923
5739
|
};
|
|
5740
|
+
return res;
|
|
4924
5741
|
}
|
|
4925
|
-
|
|
5742
|
+
getPublicParamsWasmForBits(bits) {
|
|
5743
|
+
if (bits === undefined) {
|
|
5744
|
+
throw new Error(`Missing PublicParams bits format`);
|
|
5745
|
+
}
|
|
4926
5746
|
if (bits !== 2048) {
|
|
4927
|
-
throw new Error(`Unsupported PublicParams bits format ${bits}`);
|
|
5747
|
+
throw new Error(`Unsupported PublicParams bits format '${bits}'`);
|
|
4928
5748
|
}
|
|
4929
5749
|
return {
|
|
4930
5750
|
publicParams: this._publicParamsData['2048'].publicParams,
|
|
@@ -4945,11 +5765,16 @@ async function createRelayerFhevm(config) {
|
|
|
4945
5765
|
publicParams: config.publicParams,
|
|
4946
5766
|
});
|
|
4947
5767
|
}
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
|
|
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
|
+
}
|
|
4953
5778
|
}
|
|
4954
5779
|
function _resolveRelayerUrl(value, defaultVersion) {
|
|
4955
5780
|
if (!value || typeof value !== 'string') {
|
|
@@ -5049,7 +5874,28 @@ const createInstance = async (config) => {
|
|
|
5049
5874
|
const coprocessorSigners = await getCoprocessorSigners(provider, inputVerifierContractAddress);
|
|
5050
5875
|
const thresholdCoprocessorSigners = await getCoprocessorSignersThreshold(provider, inputVerifierContractAddress);
|
|
5051
5876
|
return {
|
|
5052
|
-
createEncryptedInput: createRelayerEncryptedInput(aclContractAddress, verifyingContractAddressInputVerification, chainId, gatewayChainId, relayerFhevm.relayerProvider, relayerFhevm.getPublicKeyWasm().publicKey, { 2048: relayerFhevm.
|
|
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
|
+
},
|
|
5053
5899
|
generateKeypair,
|
|
5054
5900
|
createEIP712: createEIP712(verifyingContractAddressDecryption, chainId),
|
|
5055
5901
|
publicDecrypt: publicDecryptRequest(kmsSigners, thresholdKMSSigners, gatewayChainId, verifyingContractAddressDecryption, aclContractAddress,
|
|
@@ -5059,7 +5905,7 @@ const createInstance = async (config) => {
|
|
|
5059
5905
|
//cleanURL(config.relayerUrl),
|
|
5060
5906
|
relayerFhevm.relayerProvider, provider, auth && { auth }),
|
|
5061
5907
|
getPublicKey: () => relayerFhevm.getPublicKeyBytes(),
|
|
5062
|
-
getPublicParams: (bits) => relayerFhevm.
|
|
5908
|
+
getPublicParams: (bits) => relayerFhevm.getPublicParamsBytesForBits(bits),
|
|
5063
5909
|
// getPublicKey: () =>
|
|
5064
5910
|
// publicKeyData.publicKey
|
|
5065
5911
|
// ? {
|
|
@@ -5097,7 +5943,7 @@ const createTfheKeypair = () => {
|
|
|
5097
5943
|
};
|
|
5098
5944
|
const createTfhePublicKey = () => {
|
|
5099
5945
|
const { publicKey } = createTfheKeypair();
|
|
5100
|
-
return
|
|
5946
|
+
return bytesToHexNo0x(publicKey.serialize());
|
|
5101
5947
|
};
|
|
5102
5948
|
|
|
5103
5949
|
global.TFHE = TFHEPkg__namespace;
|