@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.js
CHANGED
|
@@ -8,7 +8,7 @@ const SERIALIZED_SIZE_LIMIT_PK = BigInt(1024 * 1024 * 512);
|
|
|
8
8
|
const SERIALIZED_SIZE_LIMIT_CRS = BigInt(1024 * 1024 * 512);
|
|
9
9
|
|
|
10
10
|
// This file is auto-generated
|
|
11
|
-
const version = '0.4.0-alpha.
|
|
11
|
+
const version = '0.4.0-alpha.2';
|
|
12
12
|
const sdkName = '@zama-fhe/relayer-sdk';
|
|
13
13
|
|
|
14
14
|
function getErrorCause(e) {
|
|
@@ -810,9 +810,9 @@ function assertRecordStringArrayProperty(o, property, objName) {
|
|
|
810
810
|
}
|
|
811
811
|
}
|
|
812
812
|
}
|
|
813
|
-
function safeJSONstringify(o) {
|
|
813
|
+
function safeJSONstringify(o, space) {
|
|
814
814
|
try {
|
|
815
|
-
return JSON.stringify(o, (_, v) => typeof v === 'bigint' ? v.toString() : v);
|
|
815
|
+
return JSON.stringify(o, (_, v) => (typeof v === 'bigint' ? v.toString() : v), space);
|
|
816
816
|
}
|
|
817
817
|
catch {
|
|
818
818
|
return '';
|
|
@@ -928,6 +928,17 @@ const NumEncryptedBits = {
|
|
|
928
928
|
7: 160, // eaddress
|
|
929
929
|
8: 256, // euint256
|
|
930
930
|
};
|
|
931
|
+
// export function getHandleType(handle: `0x${string}`): number {
|
|
932
|
+
// if (handle.length !== 66) {
|
|
933
|
+
// throw new Error(`Handle ${handle} is not of valid length`);
|
|
934
|
+
// }
|
|
935
|
+
// const hexPair = handle.slice(-4, -2).toLowerCase();
|
|
936
|
+
// const typeDiscriminant = parseInt(hexPair, 16);
|
|
937
|
+
// if (!(typeDiscriminant in NumEncryptedBits)) {
|
|
938
|
+
// throw new Error(`Handle ${handle} is not of valid type`);
|
|
939
|
+
// }
|
|
940
|
+
// return typeDiscriminant;
|
|
941
|
+
// }
|
|
931
942
|
function checkEncryptedBits(handles) {
|
|
932
943
|
let total = 0;
|
|
933
944
|
for (const handle of handles) {
|
|
@@ -985,7 +996,7 @@ function isBytes(value, bytewidth) {
|
|
|
985
996
|
if (!(value instanceof Uint8Array)) {
|
|
986
997
|
return false;
|
|
987
998
|
}
|
|
988
|
-
return value.length === bytewidth ;
|
|
999
|
+
return bytewidth ? value.length === bytewidth : true;
|
|
989
1000
|
}
|
|
990
1001
|
function isBytesHex(value, bytewidth) {
|
|
991
1002
|
if (!is0x(value)) {
|
|
@@ -1218,6 +1229,54 @@ function assertUint8ArrayProperty(o, property, objName) {
|
|
|
1218
1229
|
});
|
|
1219
1230
|
}
|
|
1220
1231
|
}
|
|
1232
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1233
|
+
// Hex
|
|
1234
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1235
|
+
const HEX_CHARS = {
|
|
1236
|
+
'0': 0,
|
|
1237
|
+
'1': 1,
|
|
1238
|
+
'2': 2,
|
|
1239
|
+
'3': 3,
|
|
1240
|
+
'4': 4,
|
|
1241
|
+
'5': 5,
|
|
1242
|
+
'6': 6,
|
|
1243
|
+
'7': 7,
|
|
1244
|
+
'8': 8,
|
|
1245
|
+
'9': 9,
|
|
1246
|
+
a: 10,
|
|
1247
|
+
b: 11,
|
|
1248
|
+
c: 12,
|
|
1249
|
+
d: 13,
|
|
1250
|
+
e: 14,
|
|
1251
|
+
f: 15,
|
|
1252
|
+
A: 10,
|
|
1253
|
+
B: 11,
|
|
1254
|
+
C: 12,
|
|
1255
|
+
D: 13,
|
|
1256
|
+
E: 14,
|
|
1257
|
+
F: 15,
|
|
1258
|
+
};
|
|
1259
|
+
Object.freeze(HEX_CHARS);
|
|
1260
|
+
const HEX_BYTES = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'));
|
|
1261
|
+
Object.freeze(HEX_BYTES);
|
|
1262
|
+
const HEX_CHARS_CODES = new Uint8Array([
|
|
1263
|
+
48,
|
|
1264
|
+
49,
|
|
1265
|
+
50,
|
|
1266
|
+
51,
|
|
1267
|
+
52,
|
|
1268
|
+
53,
|
|
1269
|
+
54,
|
|
1270
|
+
55,
|
|
1271
|
+
56,
|
|
1272
|
+
57, // '0'-'9'
|
|
1273
|
+
97,
|
|
1274
|
+
98,
|
|
1275
|
+
99,
|
|
1276
|
+
100,
|
|
1277
|
+
101,
|
|
1278
|
+
102, // 'a'-'f'
|
|
1279
|
+
]);
|
|
1221
1280
|
/**
|
|
1222
1281
|
* Convert a Uint8Array to a hex string (without 0x prefix).
|
|
1223
1282
|
*/
|
|
@@ -1237,15 +1296,49 @@ function bytesToHexNo0x(bytes) {
|
|
|
1237
1296
|
function bytesToHex(bytes) {
|
|
1238
1297
|
return `0x${bytesToHexNo0x(bytes)}`;
|
|
1239
1298
|
}
|
|
1299
|
+
function bytesToHexLarge(bytes) {
|
|
1300
|
+
const out = new Uint8Array(2 + bytes.length * 2);
|
|
1301
|
+
out[0] = 48; // '0'
|
|
1302
|
+
out[1] = 120; // 'x'
|
|
1303
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
1304
|
+
const j = 2 + i * 2;
|
|
1305
|
+
out[j] = HEX_CHARS_CODES[bytes[i] >> 4];
|
|
1306
|
+
out[j + 1] = HEX_CHARS_CODES[bytes[i] & 0xf];
|
|
1307
|
+
}
|
|
1308
|
+
return new TextDecoder().decode(out);
|
|
1309
|
+
}
|
|
1240
1310
|
/**
|
|
1241
1311
|
* Convert a hex string prefixed by 0x or not to a Uint8Array
|
|
1312
|
+
* Any invalid byte string is converted to 0
|
|
1313
|
+
* "0xzzff" = [0, 255]
|
|
1314
|
+
* "0xzfff" = [0, 255]
|
|
1242
1315
|
*/
|
|
1243
1316
|
function hexToBytes(hexString) {
|
|
1317
|
+
if (hexString.length % 2 !== 0) {
|
|
1318
|
+
throw new Error('Invalid hex string: odd length');
|
|
1319
|
+
}
|
|
1244
1320
|
const arr = hexString.replace(/^(0x)/, '').match(/.{1,2}/g);
|
|
1245
1321
|
if (!arr)
|
|
1246
1322
|
return new Uint8Array();
|
|
1247
1323
|
return Uint8Array.from(arr.map((byte) => parseInt(byte, 16)));
|
|
1248
1324
|
}
|
|
1325
|
+
function hexToBytesFaster(hexString, strict = false) {
|
|
1326
|
+
const offset = hexString[0] === '0' && hexString[1] === 'x' ? 2 : 0;
|
|
1327
|
+
const len = hexString.length - offset;
|
|
1328
|
+
if (len % 2 !== 0) {
|
|
1329
|
+
throw new Error('Invalid hex string: odd length');
|
|
1330
|
+
}
|
|
1331
|
+
const bytes = new Uint8Array(len / 2);
|
|
1332
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
1333
|
+
const hi = HEX_CHARS[hexString[offset + i * 2]];
|
|
1334
|
+
const lo = HEX_CHARS[hexString[offset + i * 2 + 1]];
|
|
1335
|
+
if ((hi === undefined || lo === undefined) && strict) {
|
|
1336
|
+
throw new Error(`Invalid hex character at position ${offset + i * 2}`);
|
|
1337
|
+
}
|
|
1338
|
+
bytes[i] = (hi << 4) | lo;
|
|
1339
|
+
}
|
|
1340
|
+
return bytes;
|
|
1341
|
+
}
|
|
1249
1342
|
/**
|
|
1250
1343
|
* Convert a Uint8Array to a bigint
|
|
1251
1344
|
*/
|
|
@@ -1259,9 +1352,6 @@ function bytesToBigInt(byteArray) {
|
|
|
1259
1352
|
}
|
|
1260
1353
|
return result;
|
|
1261
1354
|
}
|
|
1262
|
-
function toHexString(bytes, with0x = false) {
|
|
1263
|
-
return `${with0x ? '0x' : ''}${bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '')}`;
|
|
1264
|
-
}
|
|
1265
1355
|
async function fetchBytes(url) {
|
|
1266
1356
|
const response = await fetch(url);
|
|
1267
1357
|
if (!response.ok) {
|
|
@@ -1353,8 +1443,8 @@ const userDecryptRequest = (kmsSigners, gatewayChainId, chainId, verifyingContra
|
|
|
1353
1443
|
const publicKeySanitized = publicKey.replace(/^(0x)/, '');
|
|
1354
1444
|
const handleContractPairs = _handles.map((h) => ({
|
|
1355
1445
|
handle: typeof h.handle === 'string'
|
|
1356
|
-
?
|
|
1357
|
-
:
|
|
1446
|
+
? bytesToHex(hexToBytes(h.handle))
|
|
1447
|
+
: bytesToHex(h.handle),
|
|
1358
1448
|
contractAddress: getAddress$1(h.contractAddress),
|
|
1359
1449
|
}));
|
|
1360
1450
|
checkEncryptedBits(handleContractPairs.map((h) => h.handle));
|
|
@@ -1570,9 +1660,8 @@ const createEncryptedInput = ({ aclContractAddress, chainId, tfheCompactPublicKe
|
|
|
1570
1660
|
|
|
1571
1661
|
const MAX_UINT64 = BigInt('18446744073709551615'); // 2^64 - 1
|
|
1572
1662
|
BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff');
|
|
1573
|
-
const MAX_UINT32 = 0xffffffff;
|
|
1574
1663
|
const MAX_UINT8 = 0xff;
|
|
1575
|
-
function
|
|
1664
|
+
function numberToHexNo0x(num) {
|
|
1576
1665
|
let hex = num.toString(16);
|
|
1577
1666
|
return hex.length % 2 ? '0' + hex : hex;
|
|
1578
1667
|
}
|
|
@@ -1606,25 +1695,19 @@ function isUint8(value) {
|
|
|
1606
1695
|
}
|
|
1607
1696
|
return value <= MAX_UINT8;
|
|
1608
1697
|
}
|
|
1609
|
-
function isUint32(value) {
|
|
1610
|
-
if (!isUint(value)) {
|
|
1611
|
-
return false;
|
|
1612
|
-
}
|
|
1613
|
-
return value <= MAX_UINT32;
|
|
1614
|
-
}
|
|
1615
1698
|
function isUint64(value) {
|
|
1616
1699
|
if (!isUint(value)) {
|
|
1617
1700
|
return false;
|
|
1618
1701
|
}
|
|
1619
1702
|
return value <= MAX_UINT64;
|
|
1620
1703
|
}
|
|
1621
|
-
function
|
|
1622
|
-
if (!
|
|
1623
|
-
throw new InvalidTypeError({ expectedType: '
|
|
1704
|
+
function numberToBytes32(num) {
|
|
1705
|
+
if (!isUintNumber(num)) {
|
|
1706
|
+
throw new InvalidTypeError({ expectedType: 'Uint' });
|
|
1624
1707
|
}
|
|
1625
1708
|
const buffer = new ArrayBuffer(32);
|
|
1626
1709
|
const view = new DataView(buffer);
|
|
1627
|
-
view.
|
|
1710
|
+
view.setBigUint64(24, BigInt(num), false);
|
|
1628
1711
|
return new Uint8Array(buffer);
|
|
1629
1712
|
}
|
|
1630
1713
|
function assertIsUint8(value) {
|
|
@@ -1722,63 +1805,213 @@ function checksummedAddressToBytes20(address) {
|
|
|
1722
1805
|
class FhevmHandleError extends RelayerErrorBase {
|
|
1723
1806
|
constructor({ handle, message }) {
|
|
1724
1807
|
super({
|
|
1725
|
-
message: message ??
|
|
1808
|
+
message: message ??
|
|
1809
|
+
(handle
|
|
1810
|
+
? `FHEVM Handle "${handle}" is invalid.`
|
|
1811
|
+
: `FHEVM Handle is invalid.`),
|
|
1726
1812
|
name: 'FhevmHandleError',
|
|
1727
1813
|
});
|
|
1728
1814
|
}
|
|
1729
1815
|
}
|
|
1730
1816
|
|
|
1817
|
+
class FheTypeError extends RelayerErrorBase {
|
|
1818
|
+
constructor({ fheTypeId, message, }) {
|
|
1819
|
+
super({
|
|
1820
|
+
message: message ??
|
|
1821
|
+
(fheTypeId
|
|
1822
|
+
? `FheTypeId "${fheTypeId}" is invalid.`
|
|
1823
|
+
: `FheTypeId is invalid.`),
|
|
1824
|
+
name: 'FheTypeError',
|
|
1825
|
+
});
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
|
|
1829
|
+
const FheTypeIdToName = {
|
|
1830
|
+
0: 'ebool',
|
|
1831
|
+
//1: 'euint4', has been deprecated
|
|
1832
|
+
2: 'euint8',
|
|
1833
|
+
3: 'euint16',
|
|
1834
|
+
4: 'euint32',
|
|
1835
|
+
5: 'euint64',
|
|
1836
|
+
6: 'euint128',
|
|
1837
|
+
7: 'eaddress',
|
|
1838
|
+
8: 'euint256',
|
|
1839
|
+
};
|
|
1840
|
+
const FheTypeIdToEncryptionBitwidth = {
|
|
1841
|
+
0: 2,
|
|
1842
|
+
//1:?, euint4 has been deprecated
|
|
1843
|
+
2: 8,
|
|
1844
|
+
3: 16,
|
|
1845
|
+
4: 32,
|
|
1846
|
+
5: 64,
|
|
1847
|
+
6: 128,
|
|
1848
|
+
7: 160,
|
|
1849
|
+
8: 256,
|
|
1850
|
+
};
|
|
1851
|
+
const EncryptionBitwidthToFheTypeId = {
|
|
1852
|
+
2: 0,
|
|
1853
|
+
//?:1, euint4 has been deprecated
|
|
1854
|
+
8: 2,
|
|
1855
|
+
16: 3,
|
|
1856
|
+
32: 4,
|
|
1857
|
+
64: 5,
|
|
1858
|
+
128: 6,
|
|
1859
|
+
160: 7,
|
|
1860
|
+
256: 8,
|
|
1861
|
+
};
|
|
1862
|
+
const FheTypeIdToSolidityPrimitiveTypeName = {
|
|
1863
|
+
0: 'bool',
|
|
1864
|
+
//1:'uint256', euint4 has been deprecated
|
|
1865
|
+
2: 'uint256',
|
|
1866
|
+
3: 'uint256',
|
|
1867
|
+
4: 'uint256',
|
|
1868
|
+
5: 'uint256',
|
|
1869
|
+
6: 'uint256',
|
|
1870
|
+
7: 'address',
|
|
1871
|
+
8: 'uint256',
|
|
1872
|
+
};
|
|
1873
|
+
Object.freeze(FheTypeIdToEncryptionBitwidth);
|
|
1874
|
+
Object.freeze(EncryptionBitwidthToFheTypeId);
|
|
1875
|
+
Object.freeze(FheTypeIdToSolidityPrimitiveTypeName);
|
|
1876
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1877
|
+
// Type Guards
|
|
1878
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1879
|
+
/**
|
|
1880
|
+
* Checks if a value is a valid FheTypeId.
|
|
1881
|
+
* @example isFheTypeId(2) // true (euint8)
|
|
1882
|
+
* @example isFheTypeId(1) // false (euint4 is deprecated)
|
|
1883
|
+
*/
|
|
1884
|
+
function isFheTypeId(value) {
|
|
1885
|
+
switch (value) {
|
|
1886
|
+
case 0:
|
|
1887
|
+
// 1: euint4 is deprecated
|
|
1888
|
+
case 2:
|
|
1889
|
+
case 3:
|
|
1890
|
+
case 4:
|
|
1891
|
+
case 5:
|
|
1892
|
+
case 6:
|
|
1893
|
+
case 7:
|
|
1894
|
+
case 8:
|
|
1895
|
+
return true;
|
|
1896
|
+
default:
|
|
1897
|
+
return false;
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
/**
|
|
1901
|
+
* Checks if a value is a valid encryption bit width.
|
|
1902
|
+
* @example isEncryptionBits(8) // true
|
|
1903
|
+
* @example isEncryptionBits(4) // false (euint4 is deprecated)
|
|
1904
|
+
*/
|
|
1905
|
+
function isEncryptionBits(value) {
|
|
1906
|
+
if (typeof value !== 'number') {
|
|
1907
|
+
return false;
|
|
1908
|
+
}
|
|
1909
|
+
return value in EncryptionBitwidthToFheTypeId;
|
|
1910
|
+
}
|
|
1911
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1912
|
+
// FheTypeId extractors
|
|
1913
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1914
|
+
/**
|
|
1915
|
+
* Converts an encryption bit width to its corresponding FheTypeId.
|
|
1916
|
+
* @throws {FheTypeError} If bitwidth is not a valid encryption bit width.
|
|
1917
|
+
* @example fheTypeIdFromEncryptionBits(8) // 2 (euint8)
|
|
1918
|
+
*/
|
|
1919
|
+
function fheTypeIdFromEncryptionBits(bitwidth) {
|
|
1920
|
+
if (!isEncryptionBits(bitwidth)) {
|
|
1921
|
+
throw new FheTypeError({
|
|
1922
|
+
message: `Invalid encryption bits ${bitwidth}`,
|
|
1923
|
+
});
|
|
1924
|
+
}
|
|
1925
|
+
return EncryptionBitwidthToFheTypeId[bitwidth];
|
|
1926
|
+
}
|
|
1927
|
+
/**
|
|
1928
|
+
* Converts an FheTypeId to its corresponding FheTypeName.
|
|
1929
|
+
* @throws {FheTypeError} If id is not a valid FheTypeId.
|
|
1930
|
+
* @example fheTypeNameFromId(2) // 'euint8'
|
|
1931
|
+
*/
|
|
1932
|
+
function fheTypeNameFromId(id) {
|
|
1933
|
+
if (!isFheTypeId(id)) {
|
|
1934
|
+
throw new FheTypeError({
|
|
1935
|
+
message: `Invalid FheType id '${id}'`,
|
|
1936
|
+
});
|
|
1937
|
+
}
|
|
1938
|
+
return FheTypeIdToName[id];
|
|
1939
|
+
}
|
|
1940
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1941
|
+
// Solidity primitive type names
|
|
1942
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1943
|
+
/**
|
|
1944
|
+
* Returns the Solidity primitive type name for an FheTypeId.
|
|
1945
|
+
* @example solidityPrimitiveTypeNameFromFheTypeId(0) // 'bool'
|
|
1946
|
+
* @example solidityPrimitiveTypeNameFromFheTypeId(7) // 'address'
|
|
1947
|
+
* @example solidityPrimitiveTypeNameFromFheTypeId(2) // 'uint256'
|
|
1948
|
+
*/
|
|
1949
|
+
function solidityPrimitiveTypeNameFromFheTypeId(typeId) {
|
|
1950
|
+
if (!isFheTypeId(typeId)) {
|
|
1951
|
+
throw new FheTypeError({
|
|
1952
|
+
message: `Invalid FheType id '${typeId}'`,
|
|
1953
|
+
});
|
|
1954
|
+
}
|
|
1955
|
+
return FheTypeIdToSolidityPrimitiveTypeName[typeId];
|
|
1956
|
+
}
|
|
1957
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1958
|
+
// Encryption Bits
|
|
1959
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1960
|
+
/**
|
|
1961
|
+
* Returns the encryption bit width for an FheTypeId.
|
|
1962
|
+
* @example encryptionBitsFromFheTypeId(2) // 8 (euint8)
|
|
1963
|
+
* @example encryptionBitsFromFheTypeId(7) // 160 (eaddress)
|
|
1964
|
+
*/
|
|
1965
|
+
function encryptionBitsFromFheTypeId(typeId) {
|
|
1966
|
+
if (!isFheTypeId(typeId)) {
|
|
1967
|
+
throw new FheTypeError({
|
|
1968
|
+
message: `Invalid FheType id '${typeId}'`,
|
|
1969
|
+
});
|
|
1970
|
+
}
|
|
1971
|
+
return FheTypeIdToEncryptionBitwidth[typeId];
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1731
1974
|
////////////////////////////////////////////////////////////////////////////////
|
|
1732
1975
|
// FhevmHandle
|
|
1733
1976
|
////////////////////////////////////////////////////////////////////////////////
|
|
1734
1977
|
class FhevmHandle {
|
|
1978
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
1979
|
+
// Instance Properties
|
|
1980
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
1735
1981
|
_hash21;
|
|
1736
1982
|
_chainId;
|
|
1737
1983
|
_fheTypeId;
|
|
1738
1984
|
_version;
|
|
1739
1985
|
_computed;
|
|
1740
1986
|
_index;
|
|
1987
|
+
_handleBytes32Hex;
|
|
1988
|
+
_handleBytes32;
|
|
1989
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
1990
|
+
// Static Constants
|
|
1991
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
1741
1992
|
static RAW_CT_HASH_DOMAIN_SEPARATOR = 'ZK-w_rct';
|
|
1742
1993
|
static HANDLE_HASH_DOMAIN_SEPARATOR = 'ZK-w_hdl';
|
|
1743
|
-
static
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
static FheTypeEncryptionBitwidthsToId = {
|
|
1754
|
-
2: 0,
|
|
1755
|
-
8: 2,
|
|
1756
|
-
16: 3,
|
|
1757
|
-
32: 4,
|
|
1758
|
-
64: 5,
|
|
1759
|
-
128: 6,
|
|
1760
|
-
160: 7,
|
|
1761
|
-
256: 8,
|
|
1762
|
-
};
|
|
1763
|
-
static FheTypeIdToSolidityPrimitiveType = {
|
|
1764
|
-
0: 'bool',
|
|
1765
|
-
2: 'uint256',
|
|
1766
|
-
3: 'uint256',
|
|
1767
|
-
4: 'uint256',
|
|
1768
|
-
5: 'uint256',
|
|
1769
|
-
6: 'uint256',
|
|
1770
|
-
7: 'address',
|
|
1771
|
-
8: 'uint256',
|
|
1772
|
-
};
|
|
1773
|
-
static {
|
|
1774
|
-
Object.freeze(FhevmHandle.FheTypeIdToEncryptionBitwidths);
|
|
1775
|
-
Object.freeze(FhevmHandle.FheTypeEncryptionBitwidthsToId);
|
|
1776
|
-
}
|
|
1777
|
-
constructor(hash21, chainId, fheTypeId, version, computed, index) {
|
|
1994
|
+
static CURRENT_CIPHERTEXT_VERSION = 0;
|
|
1995
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
1996
|
+
// Constructor
|
|
1997
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
1998
|
+
constructor({ hash21, chainId, fheTypeId, version, computed, index, handleBytes32, handleBytes32Hex, }) {
|
|
1999
|
+
if (!isUintNumber(chainId)) {
|
|
2000
|
+
throw new FhevmHandleError({
|
|
2001
|
+
message: 'ChainId must be a positive integer',
|
|
2002
|
+
});
|
|
2003
|
+
}
|
|
1778
2004
|
if (BigInt(chainId) > MAX_UINT64) {
|
|
1779
2005
|
// fhevm assumes chainID is only taking up to 8 bytes
|
|
1780
|
-
throw new
|
|
2006
|
+
throw new FhevmHandleError({
|
|
2007
|
+
message: 'ChainId exceeds maximum allowed value (8 bytes)',
|
|
2008
|
+
});
|
|
2009
|
+
}
|
|
2010
|
+
if (!isBytesHex(hash21, 21)) {
|
|
2011
|
+
throw new FhevmHandleError({ message: 'Hash21 should be 21 bytes long' });
|
|
1781
2012
|
}
|
|
2013
|
+
this._handleBytes32 = handleBytes32;
|
|
2014
|
+
this._handleBytes32Hex = handleBytes32Hex;
|
|
1782
2015
|
this._hash21 = hash21;
|
|
1783
2016
|
this._chainId = chainId;
|
|
1784
2017
|
this._fheTypeId = fheTypeId;
|
|
@@ -1788,6 +2021,9 @@ class FhevmHandle {
|
|
|
1788
2021
|
this._index = index;
|
|
1789
2022
|
}
|
|
1790
2023
|
}
|
|
2024
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2025
|
+
// Instance Getters
|
|
2026
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
1791
2027
|
get hash21() {
|
|
1792
2028
|
return this._hash21;
|
|
1793
2029
|
}
|
|
@@ -1797,6 +2033,9 @@ class FhevmHandle {
|
|
|
1797
2033
|
get fheTypeId() {
|
|
1798
2034
|
return this._fheTypeId;
|
|
1799
2035
|
}
|
|
2036
|
+
get fheTypeName() {
|
|
2037
|
+
return fheTypeNameFromId(this._fheTypeId);
|
|
2038
|
+
}
|
|
1800
2039
|
get version() {
|
|
1801
2040
|
return this._version;
|
|
1802
2041
|
}
|
|
@@ -1806,6 +2045,106 @@ class FhevmHandle {
|
|
|
1806
2045
|
get index() {
|
|
1807
2046
|
return this._index;
|
|
1808
2047
|
}
|
|
2048
|
+
get encryptedBitwidth() {
|
|
2049
|
+
return encryptionBitsFromFheTypeId(this._fheTypeId);
|
|
2050
|
+
}
|
|
2051
|
+
get solidityPrimitiveTypeName() {
|
|
2052
|
+
return solidityPrimitiveTypeNameFromFheTypeId(this._fheTypeId);
|
|
2053
|
+
}
|
|
2054
|
+
toJSON() {
|
|
2055
|
+
return {
|
|
2056
|
+
handle: this.toBytes32Hex(),
|
|
2057
|
+
fheTypeName: this.fheTypeName,
|
|
2058
|
+
fheTypeId: this.fheTypeId,
|
|
2059
|
+
chainId: this.chainId,
|
|
2060
|
+
index: this.index,
|
|
2061
|
+
computed: this.computed,
|
|
2062
|
+
encryptedBitwidth: this.encryptedBitwidth,
|
|
2063
|
+
version: this.version,
|
|
2064
|
+
solidityPrimitiveTypeName: this.solidityPrimitiveTypeName,
|
|
2065
|
+
hash21: this.hash21,
|
|
2066
|
+
};
|
|
2067
|
+
}
|
|
2068
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2069
|
+
// Instance Serialization
|
|
2070
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2071
|
+
toBytes32() {
|
|
2072
|
+
if (this._handleBytes32 === undefined) {
|
|
2073
|
+
assertRelayer((this._index === undefined && this._computed) ||
|
|
2074
|
+
(this._index !== undefined && this._index < 255 && !this._computed));
|
|
2075
|
+
const chainId32Bytes = numberToBytes32(this._chainId);
|
|
2076
|
+
const chainId8Bytes = chainId32Bytes.subarray(24, 32);
|
|
2077
|
+
const handleHash21 = hexToBytes(this._hash21);
|
|
2078
|
+
assertRelayer(handleHash21.length === 21);
|
|
2079
|
+
const handleBytes32AsBytes = new Uint8Array(32);
|
|
2080
|
+
handleBytes32AsBytes.set(handleHash21, 0);
|
|
2081
|
+
handleBytes32AsBytes[21] = this._index === undefined ? 255 : this._index;
|
|
2082
|
+
handleBytes32AsBytes.set(chainId8Bytes, 22);
|
|
2083
|
+
handleBytes32AsBytes[30] = this._fheTypeId;
|
|
2084
|
+
handleBytes32AsBytes[31] = this._version;
|
|
2085
|
+
this._handleBytes32 = handleBytes32AsBytes;
|
|
2086
|
+
}
|
|
2087
|
+
return this._handleBytes32;
|
|
2088
|
+
}
|
|
2089
|
+
toBytes32Hex() {
|
|
2090
|
+
if (this._handleBytes32Hex === undefined) {
|
|
2091
|
+
this._handleBytes32Hex = bytesToHex(this.toBytes32());
|
|
2092
|
+
}
|
|
2093
|
+
return this._handleBytes32Hex;
|
|
2094
|
+
}
|
|
2095
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2096
|
+
// Static Factory Methods
|
|
2097
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2098
|
+
static fromComponents(params) {
|
|
2099
|
+
return new FhevmHandle(params);
|
|
2100
|
+
}
|
|
2101
|
+
static fromBytes32(handle) {
|
|
2102
|
+
if (!isBytes32(handle)) {
|
|
2103
|
+
throw new FhevmHandleError({
|
|
2104
|
+
message: `FHEVM Handle is not a valid bytes32 array.`,
|
|
2105
|
+
});
|
|
2106
|
+
}
|
|
2107
|
+
const bytes = handle;
|
|
2108
|
+
// Extract hash21 (bytes 0-20)
|
|
2109
|
+
const hash21 = bytesToHex(bytes.slice(0, 21));
|
|
2110
|
+
// Extract index (byte 21) - 255 means computed
|
|
2111
|
+
const indexByte = bytes[21];
|
|
2112
|
+
const computed = indexByte === 255;
|
|
2113
|
+
const index = computed ? undefined : indexByte;
|
|
2114
|
+
// Extract chainId (bytes 22-29, 8 bytes as big-endian uint64)
|
|
2115
|
+
let chainId = 0;
|
|
2116
|
+
for (let i = 22; i < 30; i++) {
|
|
2117
|
+
chainId = chainId * 256 + bytes[i];
|
|
2118
|
+
}
|
|
2119
|
+
// Extract fheTypeId (byte 30)
|
|
2120
|
+
const fheTypeIdByte = bytes[30];
|
|
2121
|
+
if (!isFheTypeId(fheTypeIdByte)) {
|
|
2122
|
+
throw new FhevmHandleError({
|
|
2123
|
+
handle,
|
|
2124
|
+
message: `FHEVM Handle "${handle}" is invalid. Unknown FheType: ${fheTypeIdByte}`,
|
|
2125
|
+
});
|
|
2126
|
+
}
|
|
2127
|
+
// Extract version (byte 31)
|
|
2128
|
+
const version = bytes[31];
|
|
2129
|
+
return new FhevmHandle({
|
|
2130
|
+
hash21,
|
|
2131
|
+
chainId,
|
|
2132
|
+
fheTypeId: fheTypeIdByte,
|
|
2133
|
+
version,
|
|
2134
|
+
computed,
|
|
2135
|
+
index,
|
|
2136
|
+
handleBytes32: handle,
|
|
2137
|
+
});
|
|
2138
|
+
}
|
|
2139
|
+
static fromBytes32Hex(handle) {
|
|
2140
|
+
if (!isBytes32Hex(handle)) {
|
|
2141
|
+
throw new FhevmHandleError({ handle });
|
|
2142
|
+
}
|
|
2143
|
+
const bytes = hexToBytes(handle);
|
|
2144
|
+
const h = FhevmHandle.fromBytes32(bytes);
|
|
2145
|
+
h._handleBytes32Hex = handle;
|
|
2146
|
+
return h;
|
|
2147
|
+
}
|
|
1809
2148
|
static fromZKProof(params) {
|
|
1810
2149
|
assertIsChecksummedAddress(params.aclAddress);
|
|
1811
2150
|
assertIsUint64(params.chainId);
|
|
@@ -1815,7 +2154,7 @@ class FhevmHandle {
|
|
|
1815
2154
|
fheTypeIds = params.fheTypeIds;
|
|
1816
2155
|
}
|
|
1817
2156
|
else if (params.fheTypeEncryptionBitwidths !== undefined) {
|
|
1818
|
-
fheTypeIds = params.fheTypeEncryptionBitwidths.map((w) =>
|
|
2157
|
+
fheTypeIds = params.fheTypeEncryptionBitwidths.map((w) => fheTypeIdFromEncryptionBits(w));
|
|
1819
2158
|
}
|
|
1820
2159
|
else {
|
|
1821
2160
|
throw new InternalError({
|
|
@@ -1846,22 +2185,69 @@ class FhevmHandle {
|
|
|
1846
2185
|
const handles = [];
|
|
1847
2186
|
for (let i = 0; i < fheTypeIds.length; ++i) {
|
|
1848
2187
|
const hash21 = FhevmHandle._computeInputHash21(hexToBytes(blobHashBytes32Hex), params.aclAddress, params.chainId, i);
|
|
1849
|
-
handles.push(new FhevmHandle(
|
|
2188
|
+
handles.push(new FhevmHandle({
|
|
2189
|
+
hash21,
|
|
2190
|
+
chainId: params.chainId,
|
|
2191
|
+
fheTypeId: fheTypeIds[i],
|
|
2192
|
+
version: params.ciphertextVersion,
|
|
2193
|
+
computed: false,
|
|
2194
|
+
index: i,
|
|
2195
|
+
}));
|
|
1850
2196
|
}
|
|
1851
2197
|
return handles;
|
|
1852
2198
|
}
|
|
2199
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2200
|
+
// Static Parsing
|
|
2201
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2202
|
+
static parse(handle) {
|
|
2203
|
+
if (isBytes(handle)) {
|
|
2204
|
+
return FhevmHandle.fromBytes32(handle);
|
|
2205
|
+
}
|
|
2206
|
+
return FhevmHandle.fromBytes32Hex(handle);
|
|
2207
|
+
}
|
|
2208
|
+
static canParse(handle) {
|
|
2209
|
+
try {
|
|
2210
|
+
FhevmHandle.parse(handle);
|
|
2211
|
+
return true;
|
|
2212
|
+
}
|
|
2213
|
+
catch {
|
|
2214
|
+
return false;
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
2217
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2218
|
+
// Static Assertions
|
|
2219
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2220
|
+
static assertIsHandleHex(handle) {
|
|
2221
|
+
if (typeof handle !== 'string') {
|
|
2222
|
+
throw new FhevmHandleError({
|
|
2223
|
+
message: 'Invalid bytes32 hexadecimal string',
|
|
2224
|
+
});
|
|
2225
|
+
}
|
|
2226
|
+
if (!FhevmHandle.canParse(handle)) {
|
|
2227
|
+
throw new FhevmHandleError({ handle });
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2231
|
+
// Static Helpers
|
|
2232
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2233
|
+
static currentCiphertextVersion() {
|
|
2234
|
+
return FhevmHandle.CURRENT_CIPHERTEXT_VERSION;
|
|
2235
|
+
}
|
|
2236
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
2237
|
+
// Private Helpers
|
|
2238
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
1853
2239
|
/**
|
|
1854
2240
|
* blobHashBytes32 = keccak256(ciphertextWithZKProof)
|
|
1855
2241
|
*/
|
|
1856
2242
|
static _computeInputHash21(blobHashBytes32, aclAddress, chainId, index) {
|
|
1857
2243
|
/*
|
|
1858
2244
|
https://github.com/zama-ai/fhevm/blob/8ffbd5906ab3d57af178e049930e3fc065c9d4b3/coprocessor/fhevm-engine/zkproof-worker/src/verifier.rs#L431C7-L431C8
|
|
1859
|
-
|
|
2245
|
+
|
|
1860
2246
|
handle_hash = Bytes("ZK-w_hdl") + blobHash 32 Bytes + index 1 Byte + aclAddress 20 Bytes + chainId 32 bytes
|
|
1861
2247
|
===========================================================================================================
|
|
1862
2248
|
|
|
1863
2249
|
const HANDLE_HASH_DOMAIN_SEPARATOR: [u8; 8] = *b"ZK-w_hdl";
|
|
1864
|
-
|
|
2250
|
+
|
|
1865
2251
|
let mut handle_hash = Keccak256::new();
|
|
1866
2252
|
handle_hash.update(HANDLE_HASH_DOMAIN_SEPARATOR);
|
|
1867
2253
|
handle_hash.update(blob_hash);
|
|
@@ -1882,62 +2268,12 @@ class FhevmHandle {
|
|
|
1882
2268
|
assertIsUint64(chainId);
|
|
1883
2269
|
const encryptionIndexByte1 = new Uint8Array([index]);
|
|
1884
2270
|
const aclContractAddressBytes20 = checksummedAddressToBytes20(aclAddress);
|
|
1885
|
-
const chainIdBytes32 =
|
|
2271
|
+
const chainIdBytes32 = numberToBytes32(chainId);
|
|
1886
2272
|
const encoder = new TextEncoder();
|
|
1887
2273
|
const domainSepBytes = encoder.encode(FhevmHandle.HANDLE_HASH_DOMAIN_SEPARATOR);
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
assertRelayer((this._index === undefined && this._computed) ||
|
|
1892
|
-
(this._index !== undefined && this._index < 255 && !this._computed));
|
|
1893
|
-
const chainId32Bytes = uint32ToBytes32(this._chainId);
|
|
1894
|
-
const chainId8Bytes = chainId32Bytes.subarray(24, 32);
|
|
1895
|
-
const handleHash = hexToBytes(this._hash21);
|
|
1896
|
-
const handleBytes32AsBytes = new Uint8Array(32);
|
|
1897
|
-
handleBytes32AsBytes.set(handleHash, 0);
|
|
1898
|
-
handleBytes32AsBytes[21] = this._index === undefined ? 255 : this._index;
|
|
1899
|
-
handleBytes32AsBytes.set(chainId8Bytes, 22);
|
|
1900
|
-
handleBytes32AsBytes[30] = this._fheTypeId;
|
|
1901
|
-
handleBytes32AsBytes[31] = this._version;
|
|
1902
|
-
return handleBytes32AsBytes;
|
|
1903
|
-
}
|
|
1904
|
-
toBytes32Hex() {
|
|
1905
|
-
return bytesToHex(this.toBytes32());
|
|
1906
|
-
}
|
|
1907
|
-
static checkHandleHex(handle) {
|
|
1908
|
-
if (!isBytes32Hex(handle)) {
|
|
1909
|
-
throw new FhevmHandleError({ handle });
|
|
1910
|
-
}
|
|
1911
|
-
}
|
|
1912
|
-
static isFheTypeId(value) {
|
|
1913
|
-
switch (value) {
|
|
1914
|
-
case 0:
|
|
1915
|
-
// 1: euint4 is deprecated
|
|
1916
|
-
case 2:
|
|
1917
|
-
case 3:
|
|
1918
|
-
case 4:
|
|
1919
|
-
case 5:
|
|
1920
|
-
case 6:
|
|
1921
|
-
case 7:
|
|
1922
|
-
case 8:
|
|
1923
|
-
return true;
|
|
1924
|
-
default:
|
|
1925
|
-
return false;
|
|
1926
|
-
}
|
|
1927
|
-
}
|
|
1928
|
-
static getFheTypeId(handle) {
|
|
1929
|
-
if (!isBytes32Hex(handle)) {
|
|
1930
|
-
throw new FhevmHandleError({ handle });
|
|
1931
|
-
}
|
|
1932
|
-
const hexPair = handle.slice(-4, -2).toLowerCase();
|
|
1933
|
-
const typeDiscriminant = parseInt(hexPair, 16);
|
|
1934
|
-
if (!FhevmHandle.isFheTypeId(typeDiscriminant)) {
|
|
1935
|
-
throw new FhevmHandleError({
|
|
1936
|
-
handle,
|
|
1937
|
-
message: `FHEVM Handle "${handle}" is invalid. Unknown FheType: ${typeDiscriminant}`,
|
|
1938
|
-
});
|
|
1939
|
-
}
|
|
1940
|
-
return typeDiscriminant;
|
|
2274
|
+
const hashBytes32Hex = keccak256(concatBytes(domainSepBytes, blobHashBytes32, encryptionIndexByte1, aclContractAddressBytes20, chainIdBytes32));
|
|
2275
|
+
// Truncate to 21 bytes (0x + 42 hex chars)
|
|
2276
|
+
return hashBytes32Hex.slice(0, 2 + 2 * 21);
|
|
1941
2277
|
}
|
|
1942
2278
|
}
|
|
1943
2279
|
|
|
@@ -1946,6 +2282,89 @@ const getAddress = (value) => getAddress$2(value);
|
|
|
1946
2282
|
const currentCiphertextVersion = () => {
|
|
1947
2283
|
return 0;
|
|
1948
2284
|
};
|
|
2285
|
+
async function requestCiphertextWithZKProofVerification({ bits, ciphertext, contractAddress, userAddress, aclContractAddress, verifyingContractAddressInputVerification, chainId, gatewayChainId, relayerProvider, coprocessorSigners, thresholdCoprocessorSigners, extraData, options, }) {
|
|
2286
|
+
const payload = {
|
|
2287
|
+
contractAddress,
|
|
2288
|
+
userAddress,
|
|
2289
|
+
ciphertextWithInputVerification: bytesToHexNo0x(ciphertext),
|
|
2290
|
+
contractChainId: ('0x' + chainId.toString(16)),
|
|
2291
|
+
extraData,
|
|
2292
|
+
};
|
|
2293
|
+
const json = await relayerProvider.fetchPostInputProof(payload, options);
|
|
2294
|
+
if (!isFhevmRelayerInputProofResponse(json)) {
|
|
2295
|
+
throwRelayerInternalError('INPUT_PROOF', json);
|
|
2296
|
+
}
|
|
2297
|
+
const fhevmHandles = FhevmHandle.fromZKProof({
|
|
2298
|
+
ciphertextWithZKProof: ciphertext,
|
|
2299
|
+
chainId,
|
|
2300
|
+
aclAddress: aclContractAddress,
|
|
2301
|
+
ciphertextVersion: currentCiphertextVersion(),
|
|
2302
|
+
fheTypeEncryptionBitwidths: bits,
|
|
2303
|
+
});
|
|
2304
|
+
const handles = fhevmHandles.map((h) => h.toBytes32());
|
|
2305
|
+
const result = json;
|
|
2306
|
+
// Note that the hex strings returned by the relayer do have have the 0x prefix
|
|
2307
|
+
if (result.handles && result.handles.length > 0) {
|
|
2308
|
+
const responseHandles = result.handles.map(hexToBytes);
|
|
2309
|
+
if (handles.length != responseHandles.length) {
|
|
2310
|
+
throw new Error(`Incorrect Handles list sizes: (expected) ${handles.length} != ${responseHandles.length} (received)`);
|
|
2311
|
+
}
|
|
2312
|
+
for (let index = 0; index < handles.length; index += 1) {
|
|
2313
|
+
let handle = handles[index];
|
|
2314
|
+
let responseHandle = responseHandles[index];
|
|
2315
|
+
let expected = bytesToHexNo0x(handle);
|
|
2316
|
+
let current = bytesToHexNo0x(responseHandle);
|
|
2317
|
+
if (expected !== current) {
|
|
2318
|
+
throw new Error(`Incorrect Handle ${index}: (expected) ${expected} != ${current} (received)`);
|
|
2319
|
+
}
|
|
2320
|
+
}
|
|
2321
|
+
}
|
|
2322
|
+
const signatures = result.signatures;
|
|
2323
|
+
// verify signatures for inputs:
|
|
2324
|
+
const domain = {
|
|
2325
|
+
name: 'InputVerification',
|
|
2326
|
+
version: '1',
|
|
2327
|
+
chainId: gatewayChainId,
|
|
2328
|
+
verifyingContract: verifyingContractAddressInputVerification,
|
|
2329
|
+
};
|
|
2330
|
+
const types = {
|
|
2331
|
+
CiphertextVerification: [
|
|
2332
|
+
{ name: 'ctHandles', type: 'bytes32[]' },
|
|
2333
|
+
{ name: 'userAddress', type: 'address' },
|
|
2334
|
+
{ name: 'contractAddress', type: 'address' },
|
|
2335
|
+
{ name: 'contractChainId', type: 'uint256' },
|
|
2336
|
+
{ name: 'extraData', type: 'bytes' },
|
|
2337
|
+
],
|
|
2338
|
+
};
|
|
2339
|
+
const recoveredAddresses = signatures.map((signature) => {
|
|
2340
|
+
const sig = signature.startsWith('0x') ? signature : `0x${signature}`;
|
|
2341
|
+
const recoveredAddress = ethers.verifyTypedData(domain, types, {
|
|
2342
|
+
ctHandles: handles,
|
|
2343
|
+
userAddress,
|
|
2344
|
+
contractAddress,
|
|
2345
|
+
contractChainId: chainId,
|
|
2346
|
+
extraData,
|
|
2347
|
+
}, sig);
|
|
2348
|
+
return recoveredAddress;
|
|
2349
|
+
});
|
|
2350
|
+
const thresholdReached = isThresholdReached$1(coprocessorSigners, recoveredAddresses, thresholdCoprocessorSigners);
|
|
2351
|
+
if (!thresholdReached) {
|
|
2352
|
+
throw Error('Coprocessor signers threshold is not reached');
|
|
2353
|
+
}
|
|
2354
|
+
// inputProof is len(list_handles) + numCoprocessorSigners + list_handles + signatureCoprocessorSigners (1+1+NUM_HANDLES*32+65*numSigners)
|
|
2355
|
+
let inputProof = numberToHexNo0x(handles.length);
|
|
2356
|
+
const numSigners = signatures.length;
|
|
2357
|
+
inputProof += numberToHexNo0x(numSigners);
|
|
2358
|
+
const listHandlesStr = handles.map((i) => bytesToHexNo0x(i));
|
|
2359
|
+
listHandlesStr.map((handle) => (inputProof += handle));
|
|
2360
|
+
signatures.map((signature) => (inputProof += signature.slice(2))); // removes the '0x' prefix from the `signature` string
|
|
2361
|
+
// Append the extra data to the input proof
|
|
2362
|
+
inputProof += extraData.slice(2);
|
|
2363
|
+
return {
|
|
2364
|
+
handles,
|
|
2365
|
+
inputProof: hexToBytes(inputProof),
|
|
2366
|
+
};
|
|
2367
|
+
}
|
|
1949
2368
|
function isThresholdReached$1(coprocessorSigners, recoveredAddresses, threshold) {
|
|
1950
2369
|
const addressMap = new Map();
|
|
1951
2370
|
recoveredAddresses.forEach((address, index) => {
|
|
@@ -2029,8 +2448,15 @@ const createRelayerEncryptedInput = (aclContractAddress, verifyingContractAddres
|
|
|
2029
2448
|
getBits() {
|
|
2030
2449
|
return input.getBits();
|
|
2031
2450
|
},
|
|
2032
|
-
|
|
2033
|
-
return
|
|
2451
|
+
generateZKProof() {
|
|
2452
|
+
return {
|
|
2453
|
+
chainId,
|
|
2454
|
+
aclContractAddress: aclContractAddress,
|
|
2455
|
+
userAddress: userAddress,
|
|
2456
|
+
contractAddress: contractAddress,
|
|
2457
|
+
ciphertextWithZkProof: input.encrypt(),
|
|
2458
|
+
bits: input.getBits(),
|
|
2459
|
+
};
|
|
2034
2460
|
},
|
|
2035
2461
|
encrypt: async (options) => {
|
|
2036
2462
|
const extraData = '0x00';
|
|
@@ -2039,7 +2465,7 @@ const createRelayerEncryptedInput = (aclContractAddress, verifyingContractAddres
|
|
|
2039
2465
|
const payload = {
|
|
2040
2466
|
contractAddress: getAddress(contractAddress),
|
|
2041
2467
|
userAddress: getAddress(userAddress),
|
|
2042
|
-
ciphertextWithInputVerification:
|
|
2468
|
+
ciphertextWithInputVerification: bytesToHexNo0x(ciphertext),
|
|
2043
2469
|
contractChainId: ('0x' + chainId.toString(16)),
|
|
2044
2470
|
extraData,
|
|
2045
2471
|
};
|
|
@@ -2068,8 +2494,8 @@ const createRelayerEncryptedInput = (aclContractAddress, verifyingContractAddres
|
|
|
2068
2494
|
for (let index = 0; index < handles.length; index += 1) {
|
|
2069
2495
|
let handle = handles[index];
|
|
2070
2496
|
let responseHandle = responseHandles[index];
|
|
2071
|
-
let expected =
|
|
2072
|
-
let current =
|
|
2497
|
+
let expected = bytesToHexNo0x(handle);
|
|
2498
|
+
let current = bytesToHexNo0x(responseHandle);
|
|
2073
2499
|
if (expected !== current) {
|
|
2074
2500
|
throw new Error(`Incorrect Handle ${index}: (expected) ${expected} != ${current} (received)`);
|
|
2075
2501
|
}
|
|
@@ -2108,10 +2534,10 @@ const createRelayerEncryptedInput = (aclContractAddress, verifyingContractAddres
|
|
|
2108
2534
|
throw Error('Coprocessor signers threshold is not reached');
|
|
2109
2535
|
}
|
|
2110
2536
|
// inputProof is len(list_handles) + numCoprocessorSigners + list_handles + signatureCoprocessorSigners (1+1+NUM_HANDLES*32+65*numSigners)
|
|
2111
|
-
let inputProof =
|
|
2537
|
+
let inputProof = numberToHexNo0x(handles.length);
|
|
2112
2538
|
const numSigners = signatures.length;
|
|
2113
|
-
inputProof +=
|
|
2114
|
-
const listHandlesStr = handles.map((i) =>
|
|
2539
|
+
inputProof += numberToHexNo0x(numSigners);
|
|
2540
|
+
const listHandlesStr = handles.map((i) => bytesToHexNo0x(i));
|
|
2115
2541
|
listHandlesStr.map((handle) => (inputProof += handle));
|
|
2116
2542
|
signatures.map((signature) => (inputProof += signature.slice(2))); // removes the '0x' prefix from the `signature` string
|
|
2117
2543
|
// Append the extra data to the input proof
|
|
@@ -2164,7 +2590,7 @@ function abiEncodeClearValues(clearValues) {
|
|
|
2164
2590
|
const abiValues = [];
|
|
2165
2591
|
for (let i = 0; i < handlesBytes32Hex.length; ++i) {
|
|
2166
2592
|
const handle = handlesBytes32Hex[i];
|
|
2167
|
-
const handleType = FhevmHandle.
|
|
2593
|
+
const handleType = FhevmHandle.parse(handle).fheTypeId;
|
|
2168
2594
|
let clearTextValue = clearValues[handle];
|
|
2169
2595
|
if (typeof clearTextValue === 'boolean') {
|
|
2170
2596
|
clearTextValue = clearTextValue ? '0x01' : '0x00';
|
|
@@ -2227,24 +2653,23 @@ function buildDecryptionProof(kmsSignatures, extraData) {
|
|
|
2227
2653
|
return decryptionProof;
|
|
2228
2654
|
}
|
|
2229
2655
|
function deserializeClearValues(handles, decryptedResult) {
|
|
2230
|
-
let
|
|
2656
|
+
let fheTypeIdList = [];
|
|
2231
2657
|
for (const handle of handles) {
|
|
2232
|
-
const typeDiscriminant = FhevmHandle.
|
|
2233
|
-
|
|
2234
|
-
typesList.push(typeDiscriminant);
|
|
2658
|
+
const typeDiscriminant = FhevmHandle.parse(handle).fheTypeId;
|
|
2659
|
+
fheTypeIdList.push(typeDiscriminant);
|
|
2235
2660
|
}
|
|
2236
2661
|
const restoredEncoded = '0x' +
|
|
2237
2662
|
'00'.repeat(32) + // dummy requestID (ignored)
|
|
2238
2663
|
decryptedResult.slice(2) +
|
|
2239
2664
|
'00'.repeat(32); // dummy empty bytes[] length (ignored)
|
|
2240
|
-
const abiTypes =
|
|
2241
|
-
const abiType =
|
|
2665
|
+
const abiTypes = fheTypeIdList.map((t) => {
|
|
2666
|
+
const abiType = solidityPrimitiveTypeNameFromFheTypeId(t); // all types are valid because this was supposedly checked already inside the `checkEncryptedBits` function
|
|
2242
2667
|
return abiType;
|
|
2243
2668
|
});
|
|
2244
2669
|
const coder = new AbiCoder();
|
|
2245
2670
|
const decoded = coder.decode(['uint256', ...abiTypes, 'bytes[]'], restoredEncoded);
|
|
2246
2671
|
// strip dummy first/last element
|
|
2247
|
-
const rawValues = decoded.slice(1, 1 +
|
|
2672
|
+
const rawValues = decoded.slice(1, 1 + fheTypeIdList.length);
|
|
2248
2673
|
const results = {};
|
|
2249
2674
|
handles.forEach((handle, idx) => (results[handle] = rawValues[idx]));
|
|
2250
2675
|
return results;
|
|
@@ -2252,12 +2677,13 @@ function deserializeClearValues(handles, decryptedResult) {
|
|
|
2252
2677
|
const publicDecryptRequest = (kmsSigners, thresholdSigners, gatewayChainId, verifyingContractAddress, aclContractAddress, relayerProvider, provider, defaultOptions) => async (_handles, options) => {
|
|
2253
2678
|
const extraData = '0x00';
|
|
2254
2679
|
const acl = new ethers.Contract(aclContractAddress, aclABI, provider);
|
|
2680
|
+
// This will be replaced by new sanitize classes
|
|
2255
2681
|
let handles;
|
|
2256
2682
|
try {
|
|
2257
2683
|
handles = await Promise.all(_handles.map(async (_handle) => {
|
|
2258
2684
|
const handle = typeof _handle === 'string'
|
|
2259
|
-
?
|
|
2260
|
-
:
|
|
2685
|
+
? bytesToHex(hexToBytes(_handle))
|
|
2686
|
+
: bytesToHex(_handle);
|
|
2261
2687
|
const isAllowedForDecryption = await acl.isAllowedForDecryption(handle);
|
|
2262
2688
|
if (!isAllowedForDecryption) {
|
|
2263
2689
|
throw new Error(`Handle ${handle} is not allowed for public decryption!`);
|
|
@@ -2415,8 +2841,8 @@ const createEIP712 = (verifyingContract, contractsChainId) => (publicKey, contra
|
|
|
2415
2841
|
const generateKeypair = () => {
|
|
2416
2842
|
const keypair = TKMS.ml_kem_pke_keygen();
|
|
2417
2843
|
return {
|
|
2418
|
-
publicKey:
|
|
2419
|
-
privateKey:
|
|
2844
|
+
publicKey: bytesToHexNo0x(TKMS.ml_kem_pke_pk_to_u8vec(TKMS.ml_kem_pke_get_pk(keypair))),
|
|
2845
|
+
privateKey: bytesToHexNo0x(TKMS.ml_kem_pke_sk_to_u8vec(keypair)),
|
|
2420
2846
|
};
|
|
2421
2847
|
};
|
|
2422
2848
|
|
|
@@ -3080,7 +3506,28 @@ function assertIsRelayerV2GetResponseQueued(value, name) {
|
|
|
3080
3506
|
assertRecordStringProperty(value, 'requestId', name);
|
|
3081
3507
|
}
|
|
3082
3508
|
|
|
3509
|
+
class RelayerV2TimeoutError extends RelayerV2RequestErrorBase {
|
|
3510
|
+
constructor(params) {
|
|
3511
|
+
super({
|
|
3512
|
+
...params,
|
|
3513
|
+
name: 'RelayerV2TimeoutError',
|
|
3514
|
+
message: `Request timed out after ${params.timeoutMs}ms`,
|
|
3515
|
+
});
|
|
3516
|
+
}
|
|
3517
|
+
}
|
|
3518
|
+
|
|
3519
|
+
class RelayerV2AbortError extends RelayerV2RequestErrorBase {
|
|
3520
|
+
constructor(params) {
|
|
3521
|
+
super({
|
|
3522
|
+
...params,
|
|
3523
|
+
name: 'RelayerV2AbortError',
|
|
3524
|
+
message: `Request aborted`,
|
|
3525
|
+
});
|
|
3526
|
+
}
|
|
3527
|
+
}
|
|
3528
|
+
|
|
3083
3529
|
class RelayerV2AsyncRequest {
|
|
3530
|
+
_fetchMethod;
|
|
3084
3531
|
_jobId;
|
|
3085
3532
|
_jobIdTimestamp;
|
|
3086
3533
|
_state;
|
|
@@ -3095,17 +3542,18 @@ class RelayerV2AsyncRequest {
|
|
|
3095
3542
|
_retryAfterTimeoutID;
|
|
3096
3543
|
_url;
|
|
3097
3544
|
_payload;
|
|
3098
|
-
|
|
3545
|
+
_fhevmAuth;
|
|
3099
3546
|
_retryAfterTimeoutPromiseFuncReject;
|
|
3100
3547
|
_onProgress;
|
|
3101
|
-
|
|
3548
|
+
_requestMaxDurationInMs;
|
|
3102
3549
|
_requestStartTimestamp;
|
|
3103
3550
|
_requestGlobalTimeoutID;
|
|
3104
3551
|
_throwErrorIfNoRetryAfter;
|
|
3105
|
-
static
|
|
3106
|
-
static
|
|
3107
|
-
static
|
|
3108
|
-
static
|
|
3552
|
+
static DEFAULT_RETRY_AFTER_MS = 2500;
|
|
3553
|
+
static MINIMUM_RETRY_AFTER_MS = 1000;
|
|
3554
|
+
static DEFAULT_GLOBAL_REQUEST_TIMEOUT_MS = 60 * 60 * 1000; // 1 hour
|
|
3555
|
+
static MAX_GET_RETRY = 60 * 30; // number of default retries in 1 hour (30 retries/min)
|
|
3556
|
+
static MAX_POST_RETRY = RelayerV2AsyncRequest.MAX_GET_RETRY;
|
|
3109
3557
|
constructor(params) {
|
|
3110
3558
|
if (params.relayerOperation !== 'INPUT_PROOF' &&
|
|
3111
3559
|
params.relayerOperation !== 'PUBLIC_DECRYPT' &&
|
|
@@ -3122,14 +3570,14 @@ class RelayerV2AsyncRequest {
|
|
|
3122
3570
|
this._internalAbortController = new AbortController();
|
|
3123
3571
|
this._internalAbortSignal = this._internalAbortController.signal;
|
|
3124
3572
|
this._internalAbortSignal.addEventListener('abort', this._handleInternalSignalAbort);
|
|
3125
|
-
this._externalAbortSignal = params.signal;
|
|
3573
|
+
this._externalAbortSignal = params.options?.signal;
|
|
3126
3574
|
if (this._externalAbortSignal) {
|
|
3127
3575
|
this._externalAbortSignal.addEventListener('abort', this._handleExternalSignalAbort);
|
|
3128
3576
|
}
|
|
3129
3577
|
this._url = params.url;
|
|
3130
3578
|
this._payload = params.payload;
|
|
3131
|
-
this.
|
|
3132
|
-
this._onProgress = params.onProgress;
|
|
3579
|
+
this._fhevmAuth = params.options?.auth;
|
|
3580
|
+
this._onProgress = params.options?.onProgress;
|
|
3133
3581
|
this._state = {
|
|
3134
3582
|
aborted: false,
|
|
3135
3583
|
canceled: false,
|
|
@@ -3138,6 +3586,7 @@ class RelayerV2AsyncRequest {
|
|
|
3138
3586
|
running: false,
|
|
3139
3587
|
succeeded: false,
|
|
3140
3588
|
terminated: false,
|
|
3589
|
+
timeout: false,
|
|
3141
3590
|
};
|
|
3142
3591
|
this._retryCount = 0;
|
|
3143
3592
|
this._retryAfterTimeoutID = undefined;
|
|
@@ -3145,9 +3594,9 @@ class RelayerV2AsyncRequest {
|
|
|
3145
3594
|
this._terminateReason = undefined;
|
|
3146
3595
|
this._publicAPINoReentrancy = false;
|
|
3147
3596
|
this._throwErrorIfNoRetryAfter = params.throwErrorIfNoRetryAfter ?? false;
|
|
3148
|
-
this.
|
|
3149
|
-
params.
|
|
3150
|
-
RelayerV2AsyncRequest.
|
|
3597
|
+
this._requestMaxDurationInMs =
|
|
3598
|
+
params.options?.timeout ??
|
|
3599
|
+
RelayerV2AsyncRequest.DEFAULT_GLOBAL_REQUEST_TIMEOUT_MS;
|
|
3151
3600
|
}
|
|
3152
3601
|
//////////////////////////////////////////////////////////////////////////////
|
|
3153
3602
|
// Public API: run
|
|
@@ -3189,6 +3638,12 @@ class RelayerV2AsyncRequest {
|
|
|
3189
3638
|
state: { ...this._state },
|
|
3190
3639
|
});
|
|
3191
3640
|
}
|
|
3641
|
+
if (this._state.timeout) {
|
|
3642
|
+
throw new RelayerV2StateError({
|
|
3643
|
+
message: `Relayer.run() failed. Request already timeout.`,
|
|
3644
|
+
state: { ...this._state },
|
|
3645
|
+
});
|
|
3646
|
+
}
|
|
3192
3647
|
if (this._externalAbortSignal?.aborted === true) {
|
|
3193
3648
|
throw new RelayerV2StateError({
|
|
3194
3649
|
message: `Relayer.run() failed. External AbortSignal already aborted (reason:${this._externalAbortSignal?.reason}).`,
|
|
@@ -3209,7 +3664,7 @@ class RelayerV2AsyncRequest {
|
|
|
3209
3664
|
}
|
|
3210
3665
|
this._state.running = true;
|
|
3211
3666
|
this._requestStartTimestamp = Date.now();
|
|
3212
|
-
this._setGlobalRequestTimeout(this.
|
|
3667
|
+
this._setGlobalRequestTimeout(this._requestMaxDurationInMs);
|
|
3213
3668
|
try {
|
|
3214
3669
|
const json = await this._runPostLoop();
|
|
3215
3670
|
this._state.succeeded = true;
|
|
@@ -3280,6 +3735,12 @@ class RelayerV2AsyncRequest {
|
|
|
3280
3735
|
get failed() {
|
|
3281
3736
|
return this._state.failed;
|
|
3282
3737
|
}
|
|
3738
|
+
get aborted() {
|
|
3739
|
+
return this._state.aborted;
|
|
3740
|
+
}
|
|
3741
|
+
get timeout() {
|
|
3742
|
+
return this._state.timeout;
|
|
3743
|
+
}
|
|
3283
3744
|
get succeeded() {
|
|
3284
3745
|
return this._state.succeeded;
|
|
3285
3746
|
}
|
|
@@ -3300,6 +3761,8 @@ class RelayerV2AsyncRequest {
|
|
|
3300
3761
|
//////////////////////////////////////////////////////////////////////////////
|
|
3301
3762
|
// POST : 202 | 400 | 429 | 500 | 503
|
|
3302
3763
|
async _runPostLoop() {
|
|
3764
|
+
this._assert(this._fetchMethod === undefined, 'this._fetchMethod === undefined');
|
|
3765
|
+
this._fetchMethod = 'POST';
|
|
3303
3766
|
// No infinite loop!
|
|
3304
3767
|
let i = 0;
|
|
3305
3768
|
while (i < RelayerV2AsyncRequest.MAX_POST_RETRY) {
|
|
@@ -3335,9 +3798,7 @@ class RelayerV2AsyncRequest {
|
|
|
3335
3798
|
bodyJson: safeJSONstringify(bodyJson),
|
|
3336
3799
|
});
|
|
3337
3800
|
}
|
|
3338
|
-
|
|
3339
|
-
if (retry_after_sec < 1)
|
|
3340
|
-
retry_after_sec = 1;
|
|
3801
|
+
const retryAfterMs = this._getRetryAfterHeaderValueInMs(response);
|
|
3341
3802
|
// Debug: will throw an assert failed error if jobId has already been set
|
|
3342
3803
|
this._setJobIdOnce(bodyJson.result.jobId);
|
|
3343
3804
|
// Async onProgress callback
|
|
@@ -3350,11 +3811,10 @@ class RelayerV2AsyncRequest {
|
|
|
3350
3811
|
jobId: this.jobId,
|
|
3351
3812
|
operation: this._relayerOperation,
|
|
3352
3813
|
retryCount: this._retryCount,
|
|
3353
|
-
|
|
3814
|
+
retryAfterMs,
|
|
3354
3815
|
elapsed,
|
|
3355
3816
|
});
|
|
3356
|
-
|
|
3357
|
-
await this._setRetryAfterTimeout(retry_after_sec * 1000);
|
|
3817
|
+
await this._setRetryAfterTimeout(retryAfterMs);
|
|
3358
3818
|
const json = await this._runGetLoop();
|
|
3359
3819
|
return json;
|
|
3360
3820
|
}
|
|
@@ -3400,22 +3860,20 @@ class RelayerV2AsyncRequest {
|
|
|
3400
3860
|
bodyJson: safeJSONstringify(bodyJson),
|
|
3401
3861
|
});
|
|
3402
3862
|
}
|
|
3403
|
-
|
|
3404
|
-
if (retry_after_sec < 1)
|
|
3405
|
-
retry_after_sec = 1;
|
|
3863
|
+
const retryAfterMs = this._getRetryAfterHeaderValueInMs(response);
|
|
3406
3864
|
// Async onProgress callback
|
|
3407
3865
|
this._postAsyncOnProgressCallback({
|
|
3408
3866
|
type: 'ratelimited',
|
|
3409
3867
|
url: this._url,
|
|
3410
3868
|
method: 'POST',
|
|
3411
3869
|
status: responseStatus,
|
|
3412
|
-
|
|
3870
|
+
retryAfterMs,
|
|
3413
3871
|
retryCount: this._retryCount,
|
|
3414
3872
|
elapsed,
|
|
3415
|
-
|
|
3873
|
+
relayerApiError: bodyJson.error,
|
|
3416
3874
|
});
|
|
3417
3875
|
// Wait if needed (minimum 1s)
|
|
3418
|
-
await this._setRetryAfterTimeout(
|
|
3876
|
+
await this._setRetryAfterTimeout(retryAfterMs);
|
|
3419
3877
|
continue;
|
|
3420
3878
|
}
|
|
3421
3879
|
// RelayerV2ResponseFailed
|
|
@@ -3494,8 +3952,10 @@ class RelayerV2AsyncRequest {
|
|
|
3494
3952
|
// GET: 200 | 202 | 404 | 500 | 503 | 504
|
|
3495
3953
|
// GET is not rate-limited, therefore there is not 429 error
|
|
3496
3954
|
async _runGetLoop() {
|
|
3955
|
+
this._assert(this._fetchMethod === 'POST', "this._fetchMethod === 'POST'");
|
|
3497
3956
|
this._assert(this._jobId !== undefined, 'this._jobId !== undefined');
|
|
3498
3957
|
this._assert(this._jobIdTimestamp !== undefined, 'this._jobIdTimestamp !== undefined');
|
|
3958
|
+
this._fetchMethod = 'GET';
|
|
3499
3959
|
let i = 0;
|
|
3500
3960
|
while (i < RelayerV2AsyncRequest.MAX_GET_RETRY) {
|
|
3501
3961
|
++i;
|
|
@@ -3605,9 +4065,7 @@ class RelayerV2AsyncRequest {
|
|
|
3605
4065
|
bodyJson: safeJSONstringify(bodyJson),
|
|
3606
4066
|
});
|
|
3607
4067
|
}
|
|
3608
|
-
|
|
3609
|
-
if (retry_after_sec < 1)
|
|
3610
|
-
retry_after_sec = 1;
|
|
4068
|
+
const retryAfterMs = this._getRetryAfterHeaderValueInMs(response);
|
|
3611
4069
|
// Async onProgress callback
|
|
3612
4070
|
this._postAsyncOnProgressCallback({
|
|
3613
4071
|
type: 'queued',
|
|
@@ -3617,12 +4075,12 @@ class RelayerV2AsyncRequest {
|
|
|
3617
4075
|
requestId: bodyJson.requestId,
|
|
3618
4076
|
operation: this._relayerOperation,
|
|
3619
4077
|
jobId: this.jobId,
|
|
3620
|
-
|
|
4078
|
+
retryAfterMs,
|
|
3621
4079
|
retryCount: this._retryCount,
|
|
3622
4080
|
elapsed,
|
|
3623
4081
|
});
|
|
3624
4082
|
// Wait if needed (minimum 1s)
|
|
3625
|
-
await this._setRetryAfterTimeout(
|
|
4083
|
+
await this._setRetryAfterTimeout(retryAfterMs);
|
|
3626
4084
|
continue;
|
|
3627
4085
|
}
|
|
3628
4086
|
case 400: {
|
|
@@ -3774,17 +4232,20 @@ class RelayerV2AsyncRequest {
|
|
|
3774
4232
|
return bodyJson;
|
|
3775
4233
|
}
|
|
3776
4234
|
//////////////////////////////////////////////////////////////////////////////
|
|
3777
|
-
|
|
4235
|
+
_getRetryAfterHeaderValueInMs(response) {
|
|
3778
4236
|
if (!response.headers.has('Retry-After')) {
|
|
3779
4237
|
if (this._throwErrorIfNoRetryAfter) {
|
|
3780
4238
|
throw new Error(`Missing 'Retry-After' header key`);
|
|
3781
4239
|
}
|
|
3782
|
-
return RelayerV2AsyncRequest.
|
|
4240
|
+
return RelayerV2AsyncRequest.DEFAULT_RETRY_AFTER_MS;
|
|
3783
4241
|
}
|
|
3784
4242
|
try {
|
|
3785
4243
|
const n = Number.parseInt(response.headers.get('Retry-After'));
|
|
3786
4244
|
if (isUint(n)) {
|
|
3787
|
-
|
|
4245
|
+
const ms = n * 1000;
|
|
4246
|
+
return ms < RelayerV2AsyncRequest.MINIMUM_RETRY_AFTER_MS
|
|
4247
|
+
? RelayerV2AsyncRequest.MINIMUM_RETRY_AFTER_MS
|
|
4248
|
+
: ms;
|
|
3788
4249
|
}
|
|
3789
4250
|
}
|
|
3790
4251
|
catch {
|
|
@@ -3793,7 +4254,7 @@ class RelayerV2AsyncRequest {
|
|
|
3793
4254
|
if (this._throwErrorIfNoRetryAfter) {
|
|
3794
4255
|
throw new Error(`Invalid 'Retry-After' header key`);
|
|
3795
4256
|
}
|
|
3796
|
-
return RelayerV2AsyncRequest.
|
|
4257
|
+
return RelayerV2AsyncRequest.DEFAULT_RETRY_AFTER_MS;
|
|
3797
4258
|
}
|
|
3798
4259
|
//////////////////////////////////////////////////////////////////////////////
|
|
3799
4260
|
// JobId
|
|
@@ -3832,7 +4293,7 @@ class RelayerV2AsyncRequest {
|
|
|
3832
4293
|
this._assert(this._jobId === undefined, 'this._jobId === undefined');
|
|
3833
4294
|
this._assert(!this._state.terminated, '!this._state.terminated');
|
|
3834
4295
|
this._assert(!this._state.fetching, '!this._state.fetching');
|
|
3835
|
-
this._trace('_fetchPost',
|
|
4296
|
+
this._trace('_fetchPost', this._url);
|
|
3836
4297
|
const init = setAuth({
|
|
3837
4298
|
method: 'POST',
|
|
3838
4299
|
headers: {
|
|
@@ -3844,7 +4305,7 @@ class RelayerV2AsyncRequest {
|
|
|
3844
4305
|
...(this._internalAbortSignal
|
|
3845
4306
|
? { signal: this._internalAbortSignal }
|
|
3846
4307
|
: {}),
|
|
3847
|
-
}, this.
|
|
4308
|
+
}, this._fhevmAuth);
|
|
3848
4309
|
this._state.fetching = true;
|
|
3849
4310
|
let response;
|
|
3850
4311
|
try {
|
|
@@ -3971,7 +4432,18 @@ class RelayerV2AsyncRequest {
|
|
|
3971
4432
|
if (signal.reason !== 'cancel') {
|
|
3972
4433
|
this._assert(!this._state.canceled, '!this._state.canceled');
|
|
3973
4434
|
}
|
|
3974
|
-
this.
|
|
4435
|
+
this._postAsyncOnProgressCallback({
|
|
4436
|
+
type: 'abort',
|
|
4437
|
+
url: this._url,
|
|
4438
|
+
...(this._jobId ? { jobId: this._jobId } : {}),
|
|
4439
|
+
operation: this._relayerOperation,
|
|
4440
|
+
retryCount: this._retryCount,
|
|
4441
|
+
});
|
|
4442
|
+
this._terminate('abort', new RelayerV2AbortError({
|
|
4443
|
+
operation: this._relayerOperation,
|
|
4444
|
+
jobId: this._jobId,
|
|
4445
|
+
url: this._url,
|
|
4446
|
+
}));
|
|
3975
4447
|
};
|
|
3976
4448
|
//////////////////////////////////////////////////////////////////////////////
|
|
3977
4449
|
// Terminate
|
|
@@ -3995,7 +4467,7 @@ class RelayerV2AsyncRequest {
|
|
|
3995
4467
|
this._terminateReason = reason;
|
|
3996
4468
|
this._terminateError = error;
|
|
3997
4469
|
this._state.terminated = true;
|
|
3998
|
-
this._tryClearRetryAfterTimeout();
|
|
4470
|
+
this._tryClearRetryAfterTimeout(error);
|
|
3999
4471
|
this._tryClearGlobalRequestTimeout();
|
|
4000
4472
|
const is = this._internalAbortSignal;
|
|
4001
4473
|
const es = this._externalAbortSignal;
|
|
@@ -4017,7 +4489,7 @@ class RelayerV2AsyncRequest {
|
|
|
4017
4489
|
// Debug
|
|
4018
4490
|
this._assert(!this._state.terminated, '!this._state.terminated');
|
|
4019
4491
|
this._assert(this._retryAfterTimeoutID === undefined, 'this._retryAfterTimeoutID === undefined');
|
|
4020
|
-
this._assert(delayMs >=
|
|
4492
|
+
this._assert(delayMs >= RelayerV2AsyncRequest.MINIMUM_RETRY_AFTER_MS, `delayMs >= ${RelayerV2AsyncRequest.MINIMUM_RETRY_AFTER_MS}`);
|
|
4021
4493
|
this._trace('_setRetryAfterTimeout', `delayMs=${delayMs}`);
|
|
4022
4494
|
if (this._retryAfterTimeoutID !== undefined) {
|
|
4023
4495
|
return Promise.reject(new Error(`retry-after already running.`));
|
|
@@ -4037,7 +4509,7 @@ class RelayerV2AsyncRequest {
|
|
|
4037
4509
|
return p;
|
|
4038
4510
|
}
|
|
4039
4511
|
//////////////////////////////////////////////////////////////////////////////
|
|
4040
|
-
_tryClearRetryAfterTimeout() {
|
|
4512
|
+
_tryClearRetryAfterTimeout(error) {
|
|
4041
4513
|
if (this._retryAfterTimeoutID === undefined) {
|
|
4042
4514
|
// Debug
|
|
4043
4515
|
this._assert(this._retryAfterTimeoutPromiseFuncReject === undefined, 'this._retryAfterTimeoutPromiseFuncReject === undefined');
|
|
@@ -4048,7 +4520,8 @@ class RelayerV2AsyncRequest {
|
|
|
4048
4520
|
this._retryAfterTimeoutID = undefined;
|
|
4049
4521
|
this._retryAfterTimeoutPromiseFuncReject = undefined;
|
|
4050
4522
|
clearTimeout(tid);
|
|
4051
|
-
reject
|
|
4523
|
+
// Calling reject will
|
|
4524
|
+
reject(error ?? new Error('_tryClearRetryAfterTimeout'));
|
|
4052
4525
|
}
|
|
4053
4526
|
//////////////////////////////////////////////////////////////////////////////
|
|
4054
4527
|
// Global Request Timeout
|
|
@@ -4063,7 +4536,24 @@ class RelayerV2AsyncRequest {
|
|
|
4063
4536
|
this._requestGlobalTimeoutID = setTimeout(callback, delayMs);
|
|
4064
4537
|
}
|
|
4065
4538
|
_handleGlobalRequestTimeout() {
|
|
4066
|
-
this.
|
|
4539
|
+
this._state.timeout = true;
|
|
4540
|
+
// Debug state-check guards:
|
|
4541
|
+
this._assert(this instanceof RelayerV2AsyncRequest, `this instanceof RelayerV2AsyncRequest`);
|
|
4542
|
+
this._assert(!this._state.terminated, `!this._state.terminated`);
|
|
4543
|
+
this._assert(!this._state.timeout, '!this._state.timeout');
|
|
4544
|
+
this._postAsyncOnProgressCallback({
|
|
4545
|
+
type: 'timeout',
|
|
4546
|
+
url: this._url,
|
|
4547
|
+
...(this._jobId ? { jobId: this._jobId } : {}),
|
|
4548
|
+
operation: this._relayerOperation,
|
|
4549
|
+
retryCount: this._retryCount,
|
|
4550
|
+
});
|
|
4551
|
+
this._terminate('timeout', new RelayerV2TimeoutError({
|
|
4552
|
+
operation: this._relayerOperation,
|
|
4553
|
+
jobId: this._jobId,
|
|
4554
|
+
url: this._url,
|
|
4555
|
+
timeoutMs: this._requestMaxDurationInMs,
|
|
4556
|
+
}));
|
|
4067
4557
|
}
|
|
4068
4558
|
_tryClearGlobalRequestTimeout() {
|
|
4069
4559
|
if (this._requestGlobalTimeoutID === undefined) {
|
|
@@ -4271,37 +4761,34 @@ class RelayerV2Provider extends AbstractRelayerProvider {
|
|
|
4271
4761
|
const response = await this.fetchGetKeyUrlV2();
|
|
4272
4762
|
return toRelayerV1KeyUrlResponse(response);
|
|
4273
4763
|
}
|
|
4274
|
-
async fetchPostInputProof(payload,
|
|
4764
|
+
async fetchPostInputProof(payload, options) {
|
|
4275
4765
|
const request = new RelayerV2AsyncRequest({
|
|
4276
4766
|
relayerOperation: 'INPUT_PROOF',
|
|
4277
4767
|
url: this.inputProof,
|
|
4278
4768
|
payload,
|
|
4279
|
-
|
|
4280
|
-
...fetchOptions,
|
|
4769
|
+
options,
|
|
4281
4770
|
});
|
|
4282
4771
|
const result = (await request.run());
|
|
4283
4772
|
assertIsRelayerInputProofResult(result, 'fetchPostInputProof()');
|
|
4284
4773
|
return result;
|
|
4285
4774
|
}
|
|
4286
|
-
async fetchPostPublicDecrypt(payload,
|
|
4775
|
+
async fetchPostPublicDecrypt(payload, options) {
|
|
4287
4776
|
const request = new RelayerV2AsyncRequest({
|
|
4288
4777
|
relayerOperation: 'PUBLIC_DECRYPT',
|
|
4289
4778
|
url: this.publicDecrypt,
|
|
4290
4779
|
payload,
|
|
4291
|
-
|
|
4292
|
-
...fetchOptions,
|
|
4780
|
+
options,
|
|
4293
4781
|
});
|
|
4294
4782
|
const result = await request.run();
|
|
4295
4783
|
assertIsRelayerPublicDecryptResult(result, 'fetchPostPublicDecrypt()');
|
|
4296
4784
|
return result;
|
|
4297
4785
|
}
|
|
4298
|
-
async fetchPostUserDecrypt(payload,
|
|
4786
|
+
async fetchPostUserDecrypt(payload, options) {
|
|
4299
4787
|
const request = new RelayerV2AsyncRequest({
|
|
4300
4788
|
relayerOperation: 'USER_DECRYPT',
|
|
4301
4789
|
url: this.userDecrypt,
|
|
4302
4790
|
payload,
|
|
4303
|
-
|
|
4304
|
-
...fetchOptions,
|
|
4791
|
+
options,
|
|
4305
4792
|
});
|
|
4306
4793
|
const result = (await request.run());
|
|
4307
4794
|
assertIsRelayerUserDecryptResult(result.result, 'fetchPostUserDecrypt()');
|
|
@@ -4309,6 +4796,16 @@ class RelayerV2Provider extends AbstractRelayerProvider {
|
|
|
4309
4796
|
}
|
|
4310
4797
|
}
|
|
4311
4798
|
|
|
4799
|
+
class TFHECrsError extends RelayerErrorBase {
|
|
4800
|
+
constructor({ message, cause }) {
|
|
4801
|
+
super({
|
|
4802
|
+
message,
|
|
4803
|
+
name: 'TFHECrsError',
|
|
4804
|
+
...(cause ? { cause: ensureError(cause) } : {}),
|
|
4805
|
+
});
|
|
4806
|
+
}
|
|
4807
|
+
}
|
|
4808
|
+
|
|
4312
4809
|
class AbstractRelayerFhevm {
|
|
4313
4810
|
}
|
|
4314
4811
|
|
|
@@ -4323,6 +4820,15 @@ class TFHECrs {
|
|
|
4323
4820
|
this._bits = params.bits;
|
|
4324
4821
|
this._srcUrl = params.srcUrl;
|
|
4325
4822
|
}
|
|
4823
|
+
get id() {
|
|
4824
|
+
return this._id;
|
|
4825
|
+
}
|
|
4826
|
+
get bits() {
|
|
4827
|
+
return this._bits;
|
|
4828
|
+
}
|
|
4829
|
+
get srcUrl() {
|
|
4830
|
+
return this._srcUrl;
|
|
4831
|
+
}
|
|
4326
4832
|
/*
|
|
4327
4833
|
{
|
|
4328
4834
|
id: string,
|
|
@@ -4425,19 +4931,57 @@ class TFHECrs {
|
|
|
4425
4931
|
return TFHECrs._fromUrl(params);
|
|
4426
4932
|
}
|
|
4427
4933
|
else {
|
|
4428
|
-
throw new
|
|
4934
|
+
throw new TFHECrsError({
|
|
4935
|
+
message: 'Invalid public key (deserialization failed)',
|
|
4936
|
+
});
|
|
4429
4937
|
}
|
|
4430
4938
|
}
|
|
4939
|
+
/*
|
|
4940
|
+
{
|
|
4941
|
+
id: string;
|
|
4942
|
+
data: Uint8Array;
|
|
4943
|
+
bits: number;
|
|
4944
|
+
srcUrl?: string;
|
|
4945
|
+
}
|
|
4946
|
+
*/
|
|
4431
4947
|
static fromBytes(params) {
|
|
4432
4948
|
try {
|
|
4433
4949
|
TFHECrs.assertKeyBytesType(params, 'arg');
|
|
4434
4950
|
return TFHECrs._fromBytes(params);
|
|
4435
4951
|
}
|
|
4436
4952
|
catch (e) {
|
|
4437
|
-
throw new
|
|
4953
|
+
throw new TFHECrsError({
|
|
4954
|
+
message: 'Invalid public key (deserialization failed)',
|
|
4955
|
+
cause: e,
|
|
4956
|
+
});
|
|
4957
|
+
}
|
|
4958
|
+
}
|
|
4959
|
+
/*
|
|
4960
|
+
{
|
|
4961
|
+
id: string;
|
|
4962
|
+
data: BytesHex;
|
|
4963
|
+
bits: number;
|
|
4964
|
+
srcUrl?: string;
|
|
4965
|
+
}
|
|
4966
|
+
*/
|
|
4967
|
+
static fromBytesHex(params) {
|
|
4968
|
+
let data;
|
|
4969
|
+
try {
|
|
4970
|
+
assertRecordStringProperty(params, 'data', 'arg');
|
|
4971
|
+
data = hexToBytesFaster(params.data, true /* strict */);
|
|
4972
|
+
}
|
|
4973
|
+
catch (e) {
|
|
4974
|
+
throw new TFHECrsError({
|
|
4975
|
+
message: 'Invalid public key (deserialization failed)',
|
|
4438
4976
|
cause: e,
|
|
4439
4977
|
});
|
|
4440
4978
|
}
|
|
4979
|
+
return TFHECrs.fromBytes({
|
|
4980
|
+
id: params?.id,
|
|
4981
|
+
bits: params?.bits,
|
|
4982
|
+
srcUrl: params?.srcUrl,
|
|
4983
|
+
data,
|
|
4984
|
+
});
|
|
4441
4985
|
}
|
|
4442
4986
|
static _fromBytes(params) {
|
|
4443
4987
|
const _params = {
|
|
@@ -4454,7 +4998,50 @@ class TFHECrs {
|
|
|
4454
4998
|
return TFHECrs._fromPublicParamsBytes(params);
|
|
4455
4999
|
}
|
|
4456
5000
|
catch (e) {
|
|
4457
|
-
throw new
|
|
5001
|
+
throw new TFHECrsError({
|
|
5002
|
+
message: 'Invalid public key (deserialization failed)',
|
|
5003
|
+
cause: e,
|
|
5004
|
+
});
|
|
5005
|
+
}
|
|
5006
|
+
}
|
|
5007
|
+
static fromBitsPublicParamsBytes(bits, params) {
|
|
5008
|
+
if (bits === undefined) {
|
|
5009
|
+
throw new TFHECrsError({ message: 'Missing PublicParams bits format' });
|
|
5010
|
+
}
|
|
5011
|
+
if (bits !== 2048) {
|
|
5012
|
+
throw new TFHECrsError({
|
|
5013
|
+
message: `Unsupported PublicParams bits format '${bits}'`,
|
|
5014
|
+
});
|
|
5015
|
+
}
|
|
5016
|
+
try {
|
|
5017
|
+
assertRecordStringProperty(params, 'publicParamsId', `arg`);
|
|
5018
|
+
assertUint8ArrayProperty(params, 'publicParams', `arg`);
|
|
5019
|
+
return TFHECrs._fromPublicParamsBytes({
|
|
5020
|
+
2048: params,
|
|
5021
|
+
});
|
|
5022
|
+
}
|
|
5023
|
+
catch (e) {
|
|
5024
|
+
throw new TFHECrsError({
|
|
5025
|
+
message: 'Invalid public key (deserialization failed)',
|
|
5026
|
+
cause: e,
|
|
5027
|
+
});
|
|
5028
|
+
}
|
|
5029
|
+
}
|
|
5030
|
+
static fromPublicParamsBytesHex(params) {
|
|
5031
|
+
try {
|
|
5032
|
+
assertNonNullableRecordProperty(params, '2048', 'arg');
|
|
5033
|
+
assertRecordStringProperty(params['2048'], 'publicParamsId', `arg.2048`);
|
|
5034
|
+
assertRecordStringProperty(params['2048'], 'publicParams', `arg.2048`);
|
|
5035
|
+
return TFHECrs._fromPublicParamsBytes({
|
|
5036
|
+
2048: {
|
|
5037
|
+
publicParams: hexToBytesFaster(params['2048'].publicParams, true /* strict */),
|
|
5038
|
+
publicParamsId: params['2048'].publicParamsId,
|
|
5039
|
+
},
|
|
5040
|
+
});
|
|
5041
|
+
}
|
|
5042
|
+
catch (e) {
|
|
5043
|
+
throw new TFHECrsError({
|
|
5044
|
+
message: 'Invalid public key (deserialization failed)',
|
|
4458
5045
|
cause: e,
|
|
4459
5046
|
});
|
|
4460
5047
|
}
|
|
@@ -4472,7 +5059,8 @@ class TFHECrs {
|
|
|
4472
5059
|
return TFHECrs._fromUrl(params);
|
|
4473
5060
|
}
|
|
4474
5061
|
catch (e) {
|
|
4475
|
-
throw new
|
|
5062
|
+
throw new TFHECrsError({
|
|
5063
|
+
message: 'Impossible to fetch public key: wrong relayer url.',
|
|
4476
5064
|
cause: e,
|
|
4477
5065
|
});
|
|
4478
5066
|
}
|
|
@@ -4503,6 +5091,22 @@ class TFHECrs {
|
|
|
4503
5091
|
...(this._srcUrl ? { srcUrl: this._srcUrl } : {}),
|
|
4504
5092
|
};
|
|
4505
5093
|
}
|
|
5094
|
+
/*
|
|
5095
|
+
{
|
|
5096
|
+
id: string,
|
|
5097
|
+
bits: number,
|
|
5098
|
+
data: BytesHex,
|
|
5099
|
+
srcUrl?: string
|
|
5100
|
+
}
|
|
5101
|
+
*/
|
|
5102
|
+
toBytesHex() {
|
|
5103
|
+
return {
|
|
5104
|
+
data: bytesToHexLarge(this._compactPkeCrs.safe_serialize(SERIALIZED_SIZE_LIMIT_CRS)),
|
|
5105
|
+
id: this._id,
|
|
5106
|
+
bits: this._bits,
|
|
5107
|
+
...(this._srcUrl ? { srcUrl: this._srcUrl } : {}),
|
|
5108
|
+
};
|
|
5109
|
+
}
|
|
4506
5110
|
/*
|
|
4507
5111
|
{
|
|
4508
5112
|
2048: {
|
|
@@ -4511,9 +5115,11 @@ class TFHECrs {
|
|
|
4511
5115
|
}
|
|
4512
5116
|
}
|
|
4513
5117
|
*/
|
|
4514
|
-
|
|
5118
|
+
toPublicParams2048Wasm() {
|
|
4515
5119
|
if (this._bits !== 2048) {
|
|
4516
|
-
throw new
|
|
5120
|
+
throw new TFHECrsError({
|
|
5121
|
+
message: `Unsupported PublicParams bits format '2048'`,
|
|
5122
|
+
});
|
|
4517
5123
|
}
|
|
4518
5124
|
const pp = {
|
|
4519
5125
|
2048: {
|
|
@@ -4531,9 +5137,11 @@ class TFHECrs {
|
|
|
4531
5137
|
}
|
|
4532
5138
|
}
|
|
4533
5139
|
*/
|
|
4534
|
-
|
|
5140
|
+
toPublicParams2048Bytes() {
|
|
4535
5141
|
if (this._bits !== 2048) {
|
|
4536
|
-
throw new
|
|
5142
|
+
throw new TFHECrsError({
|
|
5143
|
+
message: `Unsupported PublicParams bits format '2048'`,
|
|
5144
|
+
});
|
|
4537
5145
|
}
|
|
4538
5146
|
const pp = {
|
|
4539
5147
|
2048: {
|
|
@@ -4543,6 +5151,64 @@ class TFHECrs {
|
|
|
4543
5151
|
};
|
|
4544
5152
|
return pp;
|
|
4545
5153
|
}
|
|
5154
|
+
/*
|
|
5155
|
+
{
|
|
5156
|
+
2048: {
|
|
5157
|
+
publicParamsId: string,
|
|
5158
|
+
publicParams: BytesHex
|
|
5159
|
+
}
|
|
5160
|
+
}
|
|
5161
|
+
*/
|
|
5162
|
+
toPublicParams2048BytesHex() {
|
|
5163
|
+
if (this._bits === undefined) {
|
|
5164
|
+
throw new TFHECrsError({ message: 'Missing PublicParams bits format' });
|
|
5165
|
+
}
|
|
5166
|
+
if (this._bits !== 2048) {
|
|
5167
|
+
throw new TFHECrsError({
|
|
5168
|
+
message: `Unsupported PublicParams bits format '${this._bits}'`,
|
|
5169
|
+
});
|
|
5170
|
+
}
|
|
5171
|
+
const pp = {
|
|
5172
|
+
2048: {
|
|
5173
|
+
publicParams: this.toBytesHex().data,
|
|
5174
|
+
publicParamsId: this._id,
|
|
5175
|
+
},
|
|
5176
|
+
};
|
|
5177
|
+
return pp;
|
|
5178
|
+
}
|
|
5179
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
5180
|
+
// JSON
|
|
5181
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
5182
|
+
/*
|
|
5183
|
+
{
|
|
5184
|
+
__type: 'TFHECrs',
|
|
5185
|
+
id: string,
|
|
5186
|
+
data: BytesHex,
|
|
5187
|
+
srcUrl?: string
|
|
5188
|
+
}
|
|
5189
|
+
*/
|
|
5190
|
+
toJSON() {
|
|
5191
|
+
return {
|
|
5192
|
+
__type: 'TFHECrs',
|
|
5193
|
+
...this.toBytesHex(),
|
|
5194
|
+
};
|
|
5195
|
+
}
|
|
5196
|
+
static fromJSON(json) {
|
|
5197
|
+
if (json.__type !== 'TFHECrs') {
|
|
5198
|
+
throw new TFHECrsError({ message: 'Invalid TFHECrs JSON.' });
|
|
5199
|
+
}
|
|
5200
|
+
return TFHECrs.fromBytesHex(json);
|
|
5201
|
+
}
|
|
5202
|
+
}
|
|
5203
|
+
|
|
5204
|
+
class TFHEPublicKeyError extends RelayerErrorBase {
|
|
5205
|
+
constructor({ message, cause }) {
|
|
5206
|
+
super({
|
|
5207
|
+
message,
|
|
5208
|
+
name: 'TFHEPublicKeyError',
|
|
5209
|
+
...(cause ? { cause: ensureError(cause) } : {}),
|
|
5210
|
+
});
|
|
5211
|
+
}
|
|
4546
5212
|
}
|
|
4547
5213
|
|
|
4548
5214
|
class TFHEPublicKey {
|
|
@@ -4554,6 +5220,12 @@ class TFHEPublicKey {
|
|
|
4554
5220
|
this._tfheCompactPublicKey = params.tfheCompactPublicKey;
|
|
4555
5221
|
this._srcUrl = params.srcUrl;
|
|
4556
5222
|
}
|
|
5223
|
+
get id() {
|
|
5224
|
+
return this._id;
|
|
5225
|
+
}
|
|
5226
|
+
get srcUrl() {
|
|
5227
|
+
return this._srcUrl;
|
|
5228
|
+
}
|
|
4557
5229
|
/*
|
|
4558
5230
|
{
|
|
4559
5231
|
id: string,
|
|
@@ -4638,6 +5310,30 @@ class TFHEPublicKey {
|
|
|
4638
5310
|
});
|
|
4639
5311
|
}
|
|
4640
5312
|
}
|
|
5313
|
+
/*
|
|
5314
|
+
{
|
|
5315
|
+
id: string,
|
|
5316
|
+
data: BytesHex,
|
|
5317
|
+
srcUrl?: string
|
|
5318
|
+
}
|
|
5319
|
+
*/
|
|
5320
|
+
static fromBytesHex(params) {
|
|
5321
|
+
let data;
|
|
5322
|
+
try {
|
|
5323
|
+
assertRecordStringProperty(params, 'data', 'arg');
|
|
5324
|
+
data = hexToBytesFaster(params.data, true /* strict */);
|
|
5325
|
+
}
|
|
5326
|
+
catch (e) {
|
|
5327
|
+
throw new Error('Invalid public key (deserialization failed)', {
|
|
5328
|
+
cause: e,
|
|
5329
|
+
});
|
|
5330
|
+
}
|
|
5331
|
+
return TFHEPublicKey.fromBytes({
|
|
5332
|
+
id: params?.id,
|
|
5333
|
+
srcUrl: params?.srcUrl,
|
|
5334
|
+
data,
|
|
5335
|
+
});
|
|
5336
|
+
}
|
|
4641
5337
|
/*
|
|
4642
5338
|
{
|
|
4643
5339
|
id: string,
|
|
@@ -4698,6 +5394,20 @@ class TFHEPublicKey {
|
|
|
4698
5394
|
...(this._srcUrl ? { srcUrl: this._srcUrl } : {}),
|
|
4699
5395
|
};
|
|
4700
5396
|
}
|
|
5397
|
+
/*
|
|
5398
|
+
{
|
|
5399
|
+
id: string,
|
|
5400
|
+
data: BytesHex,
|
|
5401
|
+
srcUrl?: string
|
|
5402
|
+
}
|
|
5403
|
+
*/
|
|
5404
|
+
toBytesHex() {
|
|
5405
|
+
return {
|
|
5406
|
+
data: bytesToHexLarge(this._tfheCompactPublicKey.safe_serialize(SERIALIZED_SIZE_LIMIT_PK)),
|
|
5407
|
+
id: this._id,
|
|
5408
|
+
...(this._srcUrl ? { srcUrl: this._srcUrl } : {}),
|
|
5409
|
+
};
|
|
5410
|
+
}
|
|
4701
5411
|
/*
|
|
4702
5412
|
{
|
|
4703
5413
|
publicKey: TFHE.TfheCompactPublicKey
|
|
@@ -4722,6 +5432,75 @@ class TFHEPublicKey {
|
|
|
4722
5432
|
publicKeyId: this._id,
|
|
4723
5433
|
};
|
|
4724
5434
|
}
|
|
5435
|
+
/*
|
|
5436
|
+
{
|
|
5437
|
+
publicKey: Uint8Array
|
|
5438
|
+
publicKeyId: string
|
|
5439
|
+
}
|
|
5440
|
+
*/
|
|
5441
|
+
toPublicKeyBytesHex() {
|
|
5442
|
+
return {
|
|
5443
|
+
publicKey: this.toBytesHex().data,
|
|
5444
|
+
publicKeyId: this._id,
|
|
5445
|
+
};
|
|
5446
|
+
}
|
|
5447
|
+
static _fromPublicKeyBytes(params) {
|
|
5448
|
+
return TFHEPublicKey._fromBytes({
|
|
5449
|
+
data: params.publicKey,
|
|
5450
|
+
id: params.publicKeyId,
|
|
5451
|
+
srcUrl: params.srcUrl,
|
|
5452
|
+
});
|
|
5453
|
+
}
|
|
5454
|
+
static fromPublicKeyBytesHex(params) {
|
|
5455
|
+
try {
|
|
5456
|
+
assertRecordStringProperty(params, 'publicKey', `arg`);
|
|
5457
|
+
assertRecordStringProperty(params, 'publicKeyId', `arg`);
|
|
5458
|
+
return TFHEPublicKey._fromPublicKeyBytes({
|
|
5459
|
+
publicKey: hexToBytesFaster(params.publicKey, true /* strict */),
|
|
5460
|
+
publicKeyId: params.publicKeyId,
|
|
5461
|
+
});
|
|
5462
|
+
}
|
|
5463
|
+
catch (e) {
|
|
5464
|
+
throw new Error('Invalid public key (deserialization failed)', {
|
|
5465
|
+
cause: e,
|
|
5466
|
+
});
|
|
5467
|
+
}
|
|
5468
|
+
}
|
|
5469
|
+
static fromPublicKeyBytes(params) {
|
|
5470
|
+
try {
|
|
5471
|
+
assertUint8ArrayProperty(params, 'publicKey', `arg`);
|
|
5472
|
+
assertRecordStringProperty(params, 'publicKeyId', `arg`);
|
|
5473
|
+
return TFHEPublicKey._fromPublicKeyBytes(params);
|
|
5474
|
+
}
|
|
5475
|
+
catch (e) {
|
|
5476
|
+
throw new Error('Invalid public key (deserialization failed)', {
|
|
5477
|
+
cause: e,
|
|
5478
|
+
});
|
|
5479
|
+
}
|
|
5480
|
+
}
|
|
5481
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
5482
|
+
// JSON
|
|
5483
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
5484
|
+
/*
|
|
5485
|
+
{
|
|
5486
|
+
__type: 'TFHEPublicKey',
|
|
5487
|
+
id: string,
|
|
5488
|
+
data: BytesHex,
|
|
5489
|
+
srcUrl?: string
|
|
5490
|
+
}
|
|
5491
|
+
*/
|
|
5492
|
+
toJSON() {
|
|
5493
|
+
return {
|
|
5494
|
+
__type: 'TFHEPublicKey',
|
|
5495
|
+
...this.toBytesHex(),
|
|
5496
|
+
};
|
|
5497
|
+
}
|
|
5498
|
+
static fromJSON(json) {
|
|
5499
|
+
if (json.__type !== 'TFHEPublicKey') {
|
|
5500
|
+
throw new TFHEPublicKeyError({ message: 'Invalid TFHEPublicKey JSON.' });
|
|
5501
|
+
}
|
|
5502
|
+
return TFHEPublicKey.fromBytesHex(json);
|
|
5503
|
+
}
|
|
4725
5504
|
}
|
|
4726
5505
|
|
|
4727
5506
|
//const __KEY_URL_CACHE__: Record<string, RelayerV2PublicKey> = {};
|
|
@@ -4797,7 +5576,7 @@ class RelayerV2PublicKey {
|
|
|
4797
5576
|
toBytes() {
|
|
4798
5577
|
return {
|
|
4799
5578
|
publicKey: this._publicKey.toBytes(),
|
|
4800
|
-
publicParams: this._crs2048.
|
|
5579
|
+
publicParams: this._crs2048.toPublicParams2048Bytes(),
|
|
4801
5580
|
};
|
|
4802
5581
|
}
|
|
4803
5582
|
}
|
|
@@ -4831,23 +5610,46 @@ class RelayerV2Fhevm extends AbstractRelayerFhevm {
|
|
|
4831
5610
|
get relayerProvider() {
|
|
4832
5611
|
return this._relayerProvider;
|
|
4833
5612
|
}
|
|
5613
|
+
getPublicKeyInfo() {
|
|
5614
|
+
return {
|
|
5615
|
+
id: this._relayerPublicKey.getTFHEPublicKey().id,
|
|
5616
|
+
srcUrl: this._relayerPublicKey.getTFHEPublicKey().srcUrl,
|
|
5617
|
+
};
|
|
5618
|
+
}
|
|
4834
5619
|
getPublicKeyBytes() {
|
|
4835
5620
|
return this._relayerPublicKey.getTFHEPublicKey().toPublicKeyBytes();
|
|
4836
5621
|
}
|
|
4837
5622
|
getPublicKeyWasm() {
|
|
4838
5623
|
return this._relayerPublicKey.getTFHEPublicKey().toPublicKeyWasm();
|
|
4839
5624
|
}
|
|
4840
|
-
|
|
5625
|
+
getPublicParamsBytesForBits(bits) {
|
|
5626
|
+
if (bits === undefined) {
|
|
5627
|
+
throw new TFHECrsError({ message: `Missing PublicParams bits format` });
|
|
5628
|
+
}
|
|
4841
5629
|
if (bits !== 2048) {
|
|
4842
|
-
throw new
|
|
5630
|
+
throw new TFHECrsError({
|
|
5631
|
+
message: `Unsupported PublicParams bits format '${bits}'`,
|
|
5632
|
+
});
|
|
4843
5633
|
}
|
|
4844
|
-
return this._relayerPublicKey.getTFHECrs().
|
|
5634
|
+
return this._relayerPublicKey.getTFHECrs().toPublicParams2048Bytes()['2048'];
|
|
4845
5635
|
}
|
|
4846
|
-
|
|
5636
|
+
getPublicParamsWasmForBits(bits) {
|
|
5637
|
+
if (bits === undefined) {
|
|
5638
|
+
throw new TFHECrsError({ message: `Missing PublicParams bits format` });
|
|
5639
|
+
}
|
|
4847
5640
|
if (bits !== 2048) {
|
|
4848
|
-
throw new
|
|
5641
|
+
throw new TFHECrsError({
|
|
5642
|
+
message: `Unsupported PublicParams bits format '${bits}'`,
|
|
5643
|
+
});
|
|
4849
5644
|
}
|
|
4850
|
-
return this._relayerPublicKey.getTFHECrs().
|
|
5645
|
+
return this._relayerPublicKey.getTFHECrs().toPublicParams2048Wasm()['2048'];
|
|
5646
|
+
}
|
|
5647
|
+
getPublicParamsInfo() {
|
|
5648
|
+
return {
|
|
5649
|
+
id: this._relayerPublicKey.getTFHECrs().id,
|
|
5650
|
+
bits: this._relayerPublicKey.getTFHECrs().bits,
|
|
5651
|
+
srcUrl: this._relayerPublicKey.getTFHECrs().srcUrl,
|
|
5652
|
+
};
|
|
4851
5653
|
}
|
|
4852
5654
|
}
|
|
4853
5655
|
|
|
@@ -4886,24 +5688,42 @@ class RelayerV1Fhevm extends AbstractRelayerFhevm {
|
|
|
4886
5688
|
publicKeyId: this._publicKeyData.publicKeyId,
|
|
4887
5689
|
};
|
|
4888
5690
|
}
|
|
5691
|
+
getPublicKeyInfo() {
|
|
5692
|
+
return {
|
|
5693
|
+
id: this._publicKeyData.publicKeyId,
|
|
5694
|
+
};
|
|
5695
|
+
}
|
|
5696
|
+
getPublicParamsInfo() {
|
|
5697
|
+
return {
|
|
5698
|
+
id: this._publicParamsData['2048'].publicParamsId,
|
|
5699
|
+
bits: 2048,
|
|
5700
|
+
};
|
|
5701
|
+
}
|
|
4889
5702
|
getPublicKeyWasm() {
|
|
4890
5703
|
return {
|
|
4891
5704
|
publicKey: this._publicKeyData.publicKey,
|
|
4892
5705
|
publicKeyId: this._publicKeyData.publicKeyId,
|
|
4893
5706
|
};
|
|
4894
5707
|
}
|
|
4895
|
-
|
|
5708
|
+
getPublicParamsBytesForBits(bits) {
|
|
5709
|
+
if (bits === undefined) {
|
|
5710
|
+
throw new Error(`Missing PublicParams bits format`);
|
|
5711
|
+
}
|
|
4896
5712
|
if (bits !== 2048) {
|
|
4897
|
-
throw new Error(`Unsupported PublicParams bits format ${bits}`);
|
|
5713
|
+
throw new Error(`Unsupported PublicParams bits format '${bits}'`);
|
|
4898
5714
|
}
|
|
4899
|
-
|
|
5715
|
+
const res = {
|
|
4900
5716
|
publicParams: this._publicParamsData['2048'].publicParams.safe_serialize(SERIALIZED_SIZE_LIMIT_CRS),
|
|
4901
5717
|
publicParamsId: this._publicParamsData['2048'].publicParamsId,
|
|
4902
5718
|
};
|
|
5719
|
+
return res;
|
|
4903
5720
|
}
|
|
4904
|
-
|
|
5721
|
+
getPublicParamsWasmForBits(bits) {
|
|
5722
|
+
if (bits === undefined) {
|
|
5723
|
+
throw new Error(`Missing PublicParams bits format`);
|
|
5724
|
+
}
|
|
4905
5725
|
if (bits !== 2048) {
|
|
4906
|
-
throw new Error(`Unsupported PublicParams bits format ${bits}`);
|
|
5726
|
+
throw new Error(`Unsupported PublicParams bits format '${bits}'`);
|
|
4907
5727
|
}
|
|
4908
5728
|
return {
|
|
4909
5729
|
publicParams: this._publicParamsData['2048'].publicParams,
|
|
@@ -4924,11 +5744,16 @@ async function createRelayerFhevm(config) {
|
|
|
4924
5744
|
publicParams: config.publicParams,
|
|
4925
5745
|
});
|
|
4926
5746
|
}
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
5747
|
+
else if (resolved.version === 1) {
|
|
5748
|
+
return RelayerV1Fhevm.fromConfig({
|
|
5749
|
+
relayerVersionUrl: resolved.url,
|
|
5750
|
+
publicKey: config.publicKey,
|
|
5751
|
+
publicParams: config.publicParams,
|
|
5752
|
+
});
|
|
5753
|
+
}
|
|
5754
|
+
else {
|
|
5755
|
+
throw new Error(`Invalid relayerUrl: ${config.relayerUrl}`);
|
|
5756
|
+
}
|
|
4932
5757
|
}
|
|
4933
5758
|
function _resolveRelayerUrl(value, defaultVersion) {
|
|
4934
5759
|
if (!value || typeof value !== 'string') {
|
|
@@ -5028,7 +5853,28 @@ const createInstance = async (config) => {
|
|
|
5028
5853
|
const coprocessorSigners = await getCoprocessorSigners(provider, inputVerifierContractAddress);
|
|
5029
5854
|
const thresholdCoprocessorSigners = await getCoprocessorSignersThreshold(provider, inputVerifierContractAddress);
|
|
5030
5855
|
return {
|
|
5031
|
-
createEncryptedInput: createRelayerEncryptedInput(aclContractAddress, verifyingContractAddressInputVerification, chainId, gatewayChainId, relayerFhevm.relayerProvider, relayerFhevm.getPublicKeyWasm().publicKey, { 2048: relayerFhevm.
|
|
5856
|
+
createEncryptedInput: createRelayerEncryptedInput(aclContractAddress, verifyingContractAddressInputVerification, chainId, gatewayChainId, relayerFhevm.relayerProvider, relayerFhevm.getPublicKeyWasm().publicKey, { 2048: relayerFhevm.getPublicParamsWasmForBits(2048) }, coprocessorSigners, thresholdCoprocessorSigners, auth && { auth }),
|
|
5857
|
+
requestZKProofVerification: (zkProof, options) => {
|
|
5858
|
+
if (zkProof.chainId !== chainId ||
|
|
5859
|
+
zkProof.aclContractAddress !== aclContractAddress) {
|
|
5860
|
+
throw new Error('Invalid ZKProof');
|
|
5861
|
+
}
|
|
5862
|
+
return requestCiphertextWithZKProofVerification({
|
|
5863
|
+
ciphertext: zkProof.ciphertextWithZkProof,
|
|
5864
|
+
aclContractAddress: aclContractAddress,
|
|
5865
|
+
contractAddress: zkProof.contractAddress,
|
|
5866
|
+
userAddress: zkProof.userAddress,
|
|
5867
|
+
chainId,
|
|
5868
|
+
gatewayChainId,
|
|
5869
|
+
bits: zkProof.bits,
|
|
5870
|
+
coprocessorSigners,
|
|
5871
|
+
extraData: '0x00',
|
|
5872
|
+
thresholdCoprocessorSigners,
|
|
5873
|
+
relayerProvider: relayerFhevm.relayerProvider,
|
|
5874
|
+
verifyingContractAddressInputVerification: verifyingContractAddressInputVerification,
|
|
5875
|
+
options,
|
|
5876
|
+
});
|
|
5877
|
+
},
|
|
5032
5878
|
generateKeypair,
|
|
5033
5879
|
createEIP712: createEIP712(verifyingContractAddressDecryption, chainId),
|
|
5034
5880
|
publicDecrypt: publicDecryptRequest(kmsSigners, thresholdKMSSigners, gatewayChainId, verifyingContractAddressDecryption, aclContractAddress,
|
|
@@ -5038,7 +5884,7 @@ const createInstance = async (config) => {
|
|
|
5038
5884
|
//cleanURL(config.relayerUrl),
|
|
5039
5885
|
relayerFhevm.relayerProvider, provider, auth && { auth }),
|
|
5040
5886
|
getPublicKey: () => relayerFhevm.getPublicKeyBytes(),
|
|
5041
|
-
getPublicParams: (bits) => relayerFhevm.
|
|
5887
|
+
getPublicParams: (bits) => relayerFhevm.getPublicParamsBytesForBits(bits),
|
|
5042
5888
|
// getPublicKey: () =>
|
|
5043
5889
|
// publicKeyData.publicKey
|
|
5044
5890
|
// ? {
|
|
@@ -5076,7 +5922,7 @@ const createTfheKeypair = () => {
|
|
|
5076
5922
|
};
|
|
5077
5923
|
const createTfhePublicKey = () => {
|
|
5078
5924
|
const { publicKey } = createTfheKeypair();
|
|
5079
|
-
return
|
|
5925
|
+
return bytesToHexNo0x(publicKey.serialize());
|
|
5080
5926
|
};
|
|
5081
5927
|
|
|
5082
5928
|
global.TFHE = TFHEPkg;
|