@zama-fhe/relayer-sdk 0.3.0-3 → 0.3.0-4
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/bundle/relayer-sdk-js.js +4529 -4420
- package/bundle/relayer-sdk-js.umd.cjs +9 -9
- package/bundle.d.ts +4 -1
- package/lib/node.cjs +114 -36
- package/lib/node.d.ts +14 -4
- package/lib/node.js +114 -36
- package/lib/web.d.ts +14 -4
- package/lib/web.js +114 -36
- package/package.json +1 -1
package/bundle.d.ts
CHANGED
package/lib/node.cjs
CHANGED
|
@@ -56,6 +56,9 @@ const bytesToBigInt = function (byteArray) {
|
|
|
56
56
|
.join('');
|
|
57
57
|
return BigInt(`0x${hex}`);
|
|
58
58
|
};
|
|
59
|
+
function ensure0x(s) {
|
|
60
|
+
return !s.startsWith('0x') ? `0x${s}` : s;
|
|
61
|
+
}
|
|
59
62
|
|
|
60
63
|
function setAuth(init, auth) {
|
|
61
64
|
if (auth) {
|
|
@@ -562,6 +565,17 @@ const NumEncryptedBits = {
|
|
|
562
565
|
7: 160, // eaddress
|
|
563
566
|
8: 256, // euint256
|
|
564
567
|
};
|
|
568
|
+
function getHandleType(handle) {
|
|
569
|
+
if (handle.length !== 66) {
|
|
570
|
+
throw new Error(`Handle ${handle} is not of valid length`);
|
|
571
|
+
}
|
|
572
|
+
const hexPair = handle.slice(-4, -2).toLowerCase();
|
|
573
|
+
const typeDiscriminant = parseInt(hexPair, 16);
|
|
574
|
+
if (!(typeDiscriminant in NumEncryptedBits)) {
|
|
575
|
+
throw new Error(`Handle ${handle} is not of valid type`);
|
|
576
|
+
}
|
|
577
|
+
return typeDiscriminant;
|
|
578
|
+
}
|
|
565
579
|
function checkEncryptedBits(handles) {
|
|
566
580
|
let total = 0;
|
|
567
581
|
for (const handle of handles) {
|
|
@@ -590,37 +604,30 @@ const aclABI$1 = [
|
|
|
590
604
|
];
|
|
591
605
|
const MAX_USER_DECRYPT_CONTRACT_ADDRESSES = 10;
|
|
592
606
|
const MAX_USER_DECRYPT_DURATION_DAYS = BigInt(365);
|
|
593
|
-
function formatAccordingToType(
|
|
607
|
+
function formatAccordingToType(clearValueAsBigInt, type) {
|
|
594
608
|
if (type === 0) {
|
|
595
609
|
// ebool
|
|
596
|
-
return
|
|
610
|
+
return clearValueAsBigInt === BigInt(1);
|
|
597
611
|
}
|
|
598
612
|
else if (type === 7) {
|
|
599
613
|
// eaddress
|
|
600
|
-
return getAddress$1('0x' +
|
|
614
|
+
return getAddress$1('0x' + clearValueAsBigInt.toString(16).padStart(40, '0'));
|
|
601
615
|
}
|
|
602
|
-
else if (type
|
|
603
|
-
//
|
|
604
|
-
|
|
616
|
+
else if (type > 8 || type == 1) {
|
|
617
|
+
// type == 1 : euint4 (not supported)
|
|
618
|
+
throw new Error(`Unsupported handle type ${type}`);
|
|
605
619
|
}
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
return '0x' + decryptedBigInt.toString(16).padStart(256, '0');
|
|
609
|
-
}
|
|
610
|
-
else if (type === 11) {
|
|
611
|
-
// ebytes256
|
|
612
|
-
return '0x' + decryptedBigInt.toString(16).padStart(512, '0');
|
|
613
|
-
} // euintXXX
|
|
614
|
-
return decryptedBigInt;
|
|
620
|
+
// euintXXX
|
|
621
|
+
return clearValueAsBigInt;
|
|
615
622
|
}
|
|
616
|
-
function
|
|
623
|
+
function buildUserDecryptResults(handles, listBigIntDecryptions) {
|
|
617
624
|
let typesList = [];
|
|
618
625
|
for (const handle of handles) {
|
|
619
626
|
const hexPair = handle.slice(-4, -2).toLowerCase();
|
|
620
627
|
const typeDiscriminant = parseInt(hexPair, 16);
|
|
621
628
|
typesList.push(typeDiscriminant);
|
|
622
629
|
}
|
|
623
|
-
|
|
630
|
+
const results = {};
|
|
624
631
|
handles.forEach((handle, idx) => (results[handle] = formatAccordingToType(listBigIntDecryptions[idx], typesList[idx])));
|
|
625
632
|
return results;
|
|
626
633
|
}
|
|
@@ -726,7 +733,7 @@ const userDecryptRequest = (kmsSigners, gatewayChainId, chainId, verifyingContra
|
|
|
726
733
|
};
|
|
727
734
|
const decryption = TKMS.process_user_decryption_resp_from_js(client, payloadForVerification, eip712Domain, json.response, pubKey, privKey, true);
|
|
728
735
|
const listBigIntDecryptions = decryption.map((d) => bytesToBigInt(d.bytes));
|
|
729
|
-
const results =
|
|
736
|
+
const results = buildUserDecryptResults(handles.map((h) => h.handle), listBigIntDecryptions);
|
|
730
737
|
return results;
|
|
731
738
|
}
|
|
732
739
|
catch (e) {
|
|
@@ -1137,6 +1144,74 @@ function isThresholdReached(kmsSigners, recoveredAddresses, threshold) {
|
|
|
1137
1144
|
}
|
|
1138
1145
|
return recoveredAddresses.length >= threshold;
|
|
1139
1146
|
}
|
|
1147
|
+
function abiEncodeClearValues(clearValues) {
|
|
1148
|
+
const handlesBytes32Hex = Object.keys(clearValues);
|
|
1149
|
+
const abiTypes = [];
|
|
1150
|
+
const abiValues = [];
|
|
1151
|
+
for (let i = 0; i < handlesBytes32Hex.length; ++i) {
|
|
1152
|
+
const handle = handlesBytes32Hex[i];
|
|
1153
|
+
const handleType = getHandleType(handle);
|
|
1154
|
+
let clearTextValue = clearValues[handle];
|
|
1155
|
+
if (typeof clearTextValue === 'boolean') {
|
|
1156
|
+
clearTextValue = clearTextValue ? '0x01' : '0x00';
|
|
1157
|
+
}
|
|
1158
|
+
const clearTextValueBigInt = BigInt(clearTextValue);
|
|
1159
|
+
//abiTypes.push(fhevmTypeInfo.solidityTypeName);
|
|
1160
|
+
abiTypes.push('uint256');
|
|
1161
|
+
switch (handleType) {
|
|
1162
|
+
// eaddress
|
|
1163
|
+
case 7: {
|
|
1164
|
+
// string
|
|
1165
|
+
abiValues.push(`0x${clearTextValueBigInt.toString(16).padStart(40, '0')}`);
|
|
1166
|
+
break;
|
|
1167
|
+
}
|
|
1168
|
+
// ebool
|
|
1169
|
+
case 0: {
|
|
1170
|
+
// bigint (0 or 1)
|
|
1171
|
+
if (clearTextValueBigInt !== BigInt(0) &&
|
|
1172
|
+
clearTextValueBigInt !== BigInt(1)) {
|
|
1173
|
+
throw new Error(`Invalid ebool clear text value ${clearTextValueBigInt}. Expecting 0 or 1.`);
|
|
1174
|
+
}
|
|
1175
|
+
abiValues.push(clearTextValueBigInt);
|
|
1176
|
+
break;
|
|
1177
|
+
}
|
|
1178
|
+
case 2: //euint8
|
|
1179
|
+
case 3: //euint16
|
|
1180
|
+
case 4: //euint32
|
|
1181
|
+
case 5: //euint64
|
|
1182
|
+
case 6: //euint128
|
|
1183
|
+
case 7: {
|
|
1184
|
+
//euint256
|
|
1185
|
+
// bigint
|
|
1186
|
+
abiValues.push(clearTextValueBigInt);
|
|
1187
|
+
break;
|
|
1188
|
+
}
|
|
1189
|
+
default: {
|
|
1190
|
+
throw new Error(`Unsupported Fhevm primitive type id: ${handleType}`);
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
const abiCoder = ethers.ethers.AbiCoder.defaultAbiCoder();
|
|
1195
|
+
// ABI encode the decryptedResult as done in the KMS, since all decrypted values
|
|
1196
|
+
// are native static types, thay have same abi-encoding as uint256:
|
|
1197
|
+
const abiEncodedClearValues = abiCoder.encode(abiTypes, abiValues);
|
|
1198
|
+
return {
|
|
1199
|
+
abiTypes,
|
|
1200
|
+
abiValues,
|
|
1201
|
+
abiEncodedClearValues,
|
|
1202
|
+
};
|
|
1203
|
+
}
|
|
1204
|
+
function buildDecryptionProof(kmsSignatures, extraData) {
|
|
1205
|
+
// Build the decryptionProof as numSigners + KMS signatures + extraData
|
|
1206
|
+
const packedNumSigners = ethers.ethers.solidityPacked(['uint8'], [kmsSignatures.length]);
|
|
1207
|
+
const packedSignatures = ethers.ethers.solidityPacked(Array(kmsSignatures.length).fill('bytes'), kmsSignatures);
|
|
1208
|
+
const decryptionProof = ethers.ethers.concat([
|
|
1209
|
+
packedNumSigners,
|
|
1210
|
+
packedSignatures,
|
|
1211
|
+
extraData,
|
|
1212
|
+
]);
|
|
1213
|
+
return decryptionProof;
|
|
1214
|
+
}
|
|
1140
1215
|
const CiphertextType = {
|
|
1141
1216
|
0: 'bool',
|
|
1142
1217
|
2: 'uint256',
|
|
@@ -1147,7 +1222,7 @@ const CiphertextType = {
|
|
|
1147
1222
|
7: 'address',
|
|
1148
1223
|
8: 'uint256',
|
|
1149
1224
|
};
|
|
1150
|
-
function
|
|
1225
|
+
function deserializeClearValues(handles, decryptedResult) {
|
|
1151
1226
|
let typesList = [];
|
|
1152
1227
|
for (const handle of handles) {
|
|
1153
1228
|
const hexPair = handle.slice(-4, -2).toLowerCase();
|
|
@@ -1166,7 +1241,7 @@ function deserializeDecryptedResult(handles, decryptedResult) {
|
|
|
1166
1241
|
const decoded = coder.decode(['uint256', ...abiTypes, 'bytes[]'], restoredEncoded);
|
|
1167
1242
|
// strip dummy first/last element
|
|
1168
1243
|
const rawValues = decoded.slice(1, 1 + typesList.length);
|
|
1169
|
-
|
|
1244
|
+
const results = {};
|
|
1170
1245
|
handles.forEach((handle, idx) => (results[handle] = rawValues[idx]));
|
|
1171
1246
|
return results;
|
|
1172
1247
|
}
|
|
@@ -1211,22 +1286,25 @@ const publicDecryptRequest = (kmsSigners, thresholdSigners, gatewayChainId, veri
|
|
|
1211
1286
|
],
|
|
1212
1287
|
};
|
|
1213
1288
|
const result = json.response[0];
|
|
1214
|
-
const decryptedResult = result.decrypted_value
|
|
1215
|
-
|
|
1216
|
-
: `0x${result.decrypted_value}`;
|
|
1217
|
-
const signatures = result.signatures;
|
|
1289
|
+
const decryptedResult = ensure0x(result.decrypted_value);
|
|
1290
|
+
const kmsSignatures = result.signatures.map(ensure0x);
|
|
1218
1291
|
const signedExtraData = '0x';
|
|
1219
|
-
const recoveredAddresses =
|
|
1220
|
-
const
|
|
1221
|
-
const recoveredAddress = ethers.ethers.verifyTypedData(domain, types, { ctHandles: handles, decryptedResult, extraData: signedExtraData }, sig);
|
|
1292
|
+
const recoveredAddresses = kmsSignatures.map((kmsSignature) => {
|
|
1293
|
+
const recoveredAddress = ethers.ethers.verifyTypedData(domain, types, { ctHandles: handles, decryptedResult, extraData: signedExtraData }, kmsSignature);
|
|
1222
1294
|
return recoveredAddress;
|
|
1223
1295
|
});
|
|
1224
1296
|
const thresholdReached = isThresholdReached(kmsSigners, recoveredAddresses, thresholdSigners);
|
|
1225
1297
|
if (!thresholdReached) {
|
|
1226
1298
|
throw Error('KMS signers threshold is not reached');
|
|
1227
1299
|
}
|
|
1228
|
-
const
|
|
1229
|
-
|
|
1300
|
+
const clearValues = deserializeClearValues(handles, decryptedResult);
|
|
1301
|
+
const abiEnc = abiEncodeClearValues(clearValues);
|
|
1302
|
+
const decryptionProof = buildDecryptionProof(kmsSignatures, signedExtraData);
|
|
1303
|
+
return {
|
|
1304
|
+
clearValues,
|
|
1305
|
+
abiEncodedClearValues: abiEnc.abiEncodedClearValues,
|
|
1306
|
+
decryptionProof,
|
|
1307
|
+
};
|
|
1230
1308
|
};
|
|
1231
1309
|
|
|
1232
1310
|
/**
|
|
@@ -1336,23 +1414,23 @@ const generateKeypair = () => {
|
|
|
1336
1414
|
global.fetch = fetchRetry(global.fetch, { retries: 5, retryDelay: 500 });
|
|
1337
1415
|
const SepoliaConfig = {
|
|
1338
1416
|
// ACL_CONTRACT_ADDRESS (FHEVM Host chain)
|
|
1339
|
-
aclContractAddress: '
|
|
1417
|
+
aclContractAddress: '0xf0Ffdc93b7E186bC2f8CB3dAA75D86d1930A433D',
|
|
1340
1418
|
// KMS_VERIFIER_CONTRACT_ADDRESS (FHEVM Host chain)
|
|
1341
|
-
kmsContractAddress: '
|
|
1419
|
+
kmsContractAddress: '0xbE0E383937d564D7FF0BC3b46c51f0bF8d5C311A',
|
|
1342
1420
|
// INPUT_VERIFIER_CONTRACT_ADDRESS (FHEVM Host chain)
|
|
1343
|
-
inputVerifierContractAddress: '
|
|
1421
|
+
inputVerifierContractAddress: '0xBBC1fFCdc7C316aAAd72E807D9b0272BE8F84DA0',
|
|
1344
1422
|
// DECRYPTION_ADDRESS (Gateway chain)
|
|
1345
|
-
verifyingContractAddressDecryption: '
|
|
1423
|
+
verifyingContractAddressDecryption: '0x5D8BD78e2ea6bbE41f26dFe9fdaEAa349e077478',
|
|
1346
1424
|
// INPUT_VERIFICATION_ADDRESS (Gateway chain)
|
|
1347
|
-
verifyingContractAddressInputVerification: '
|
|
1425
|
+
verifyingContractAddressInputVerification: '0x483b9dE06E4E4C7D35CCf5837A1668487406D955',
|
|
1348
1426
|
// FHEVM Host chain id
|
|
1349
1427
|
chainId: 11155111,
|
|
1350
1428
|
// Gateway chain id
|
|
1351
|
-
gatewayChainId:
|
|
1429
|
+
gatewayChainId: 10901,
|
|
1352
1430
|
// Optional RPC provider to host chain
|
|
1353
1431
|
network: 'https://eth-sepolia.public.blastapi.io',
|
|
1354
1432
|
// Relayer URL
|
|
1355
|
-
relayerUrl: 'https://relayer.testnet.zama.
|
|
1433
|
+
relayerUrl: 'https://relayer.testnet.zama.org',
|
|
1356
1434
|
};
|
|
1357
1435
|
const createInstance = async (config) => {
|
|
1358
1436
|
const { verifyingContractAddressDecryption, verifyingContractAddressInputVerification, publicKey, kmsContractAddress, aclContractAddress, gatewayChainId, auth, } = config;
|
package/lib/node.d.ts
CHANGED
|
@@ -53,6 +53,10 @@ declare type BearerToken = {
|
|
|
53
53
|
token: string;
|
|
54
54
|
};
|
|
55
55
|
|
|
56
|
+
export declare type ClearValues = Record<`0x${string}`, ClearValueType>;
|
|
57
|
+
|
|
58
|
+
export declare type ClearValueType = bigint | boolean | `0x${string}`;
|
|
59
|
+
|
|
56
60
|
/**
|
|
57
61
|
* Creates an EIP712 structure specifically for user decrypt requests
|
|
58
62
|
*
|
|
@@ -78,8 +82,6 @@ export declare const createTfheKeypair: () => {
|
|
|
78
82
|
|
|
79
83
|
export declare const createTfhePublicKey: () => string;
|
|
80
84
|
|
|
81
|
-
export declare type DecryptedResults = Record<string, bigint | boolean | string>;
|
|
82
|
-
|
|
83
85
|
export declare type EIP712 = {
|
|
84
86
|
domain: {
|
|
85
87
|
chainId: number;
|
|
@@ -122,8 +124,8 @@ export declare type FhevmInstance = {
|
|
|
122
124
|
privateKey: string;
|
|
123
125
|
};
|
|
124
126
|
createEIP712: (publicKey: string, contractAddresses: string[], startTimestamp: string | number, durationDays: string | number) => EIP712;
|
|
125
|
-
publicDecrypt: (handles: (string | Uint8Array)[]) => Promise<
|
|
126
|
-
userDecrypt: (handles: HandleContractPair[], privateKey: string, publicKey: string, signature: string, contractAddresses: string[], userAddress: string, startTimestamp: string | number, durationDays: string | number) => Promise<
|
|
127
|
+
publicDecrypt: (handles: (string | Uint8Array)[]) => Promise<PublicDecryptResults>;
|
|
128
|
+
userDecrypt: (handles: HandleContractPair[], privateKey: string, publicKey: string, signature: string, contractAddresses: string[], userAddress: string, startTimestamp: string | number, durationDays: string | number) => Promise<UserDecryptResults>;
|
|
127
129
|
getPublicKey: () => {
|
|
128
130
|
publicKeyId: string;
|
|
129
131
|
publicKey: Uint8Array;
|
|
@@ -166,6 +168,12 @@ export declare type HandleContractPair = {
|
|
|
166
168
|
contractAddress: string;
|
|
167
169
|
};
|
|
168
170
|
|
|
171
|
+
export declare type PublicDecryptResults = {
|
|
172
|
+
clearValues: ClearValues;
|
|
173
|
+
abiEncodedClearValues: `0x${string}`;
|
|
174
|
+
decryptionProof: `0x${string}`;
|
|
175
|
+
};
|
|
176
|
+
|
|
169
177
|
export declare type PublicParams<T = TFHEType['CompactPkeCrs']> = {
|
|
170
178
|
[key in EncryptionTypes]?: {
|
|
171
179
|
publicParams: T;
|
|
@@ -204,4 +212,6 @@ export declare type TFHEType = {
|
|
|
204
212
|
ZkComputeLoad: any;
|
|
205
213
|
};
|
|
206
214
|
|
|
215
|
+
export declare type UserDecryptResults = ClearValues;
|
|
216
|
+
|
|
207
217
|
export { }
|
package/lib/node.js
CHANGED
|
@@ -35,6 +35,9 @@ const bytesToBigInt = function (byteArray) {
|
|
|
35
35
|
.join('');
|
|
36
36
|
return BigInt(`0x${hex}`);
|
|
37
37
|
};
|
|
38
|
+
function ensure0x(s) {
|
|
39
|
+
return !s.startsWith('0x') ? `0x${s}` : s;
|
|
40
|
+
}
|
|
38
41
|
|
|
39
42
|
function setAuth(init, auth) {
|
|
40
43
|
if (auth) {
|
|
@@ -541,6 +544,17 @@ const NumEncryptedBits = {
|
|
|
541
544
|
7: 160, // eaddress
|
|
542
545
|
8: 256, // euint256
|
|
543
546
|
};
|
|
547
|
+
function getHandleType(handle) {
|
|
548
|
+
if (handle.length !== 66) {
|
|
549
|
+
throw new Error(`Handle ${handle} is not of valid length`);
|
|
550
|
+
}
|
|
551
|
+
const hexPair = handle.slice(-4, -2).toLowerCase();
|
|
552
|
+
const typeDiscriminant = parseInt(hexPair, 16);
|
|
553
|
+
if (!(typeDiscriminant in NumEncryptedBits)) {
|
|
554
|
+
throw new Error(`Handle ${handle} is not of valid type`);
|
|
555
|
+
}
|
|
556
|
+
return typeDiscriminant;
|
|
557
|
+
}
|
|
544
558
|
function checkEncryptedBits(handles) {
|
|
545
559
|
let total = 0;
|
|
546
560
|
for (const handle of handles) {
|
|
@@ -569,37 +583,30 @@ const aclABI$1 = [
|
|
|
569
583
|
];
|
|
570
584
|
const MAX_USER_DECRYPT_CONTRACT_ADDRESSES = 10;
|
|
571
585
|
const MAX_USER_DECRYPT_DURATION_DAYS = BigInt(365);
|
|
572
|
-
function formatAccordingToType(
|
|
586
|
+
function formatAccordingToType(clearValueAsBigInt, type) {
|
|
573
587
|
if (type === 0) {
|
|
574
588
|
// ebool
|
|
575
|
-
return
|
|
589
|
+
return clearValueAsBigInt === BigInt(1);
|
|
576
590
|
}
|
|
577
591
|
else if (type === 7) {
|
|
578
592
|
// eaddress
|
|
579
|
-
return getAddress$1('0x' +
|
|
593
|
+
return getAddress$1('0x' + clearValueAsBigInt.toString(16).padStart(40, '0'));
|
|
580
594
|
}
|
|
581
|
-
else if (type
|
|
582
|
-
//
|
|
583
|
-
|
|
595
|
+
else if (type > 8 || type == 1) {
|
|
596
|
+
// type == 1 : euint4 (not supported)
|
|
597
|
+
throw new Error(`Unsupported handle type ${type}`);
|
|
584
598
|
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
return '0x' + decryptedBigInt.toString(16).padStart(256, '0');
|
|
588
|
-
}
|
|
589
|
-
else if (type === 11) {
|
|
590
|
-
// ebytes256
|
|
591
|
-
return '0x' + decryptedBigInt.toString(16).padStart(512, '0');
|
|
592
|
-
} // euintXXX
|
|
593
|
-
return decryptedBigInt;
|
|
599
|
+
// euintXXX
|
|
600
|
+
return clearValueAsBigInt;
|
|
594
601
|
}
|
|
595
|
-
function
|
|
602
|
+
function buildUserDecryptResults(handles, listBigIntDecryptions) {
|
|
596
603
|
let typesList = [];
|
|
597
604
|
for (const handle of handles) {
|
|
598
605
|
const hexPair = handle.slice(-4, -2).toLowerCase();
|
|
599
606
|
const typeDiscriminant = parseInt(hexPair, 16);
|
|
600
607
|
typesList.push(typeDiscriminant);
|
|
601
608
|
}
|
|
602
|
-
|
|
609
|
+
const results = {};
|
|
603
610
|
handles.forEach((handle, idx) => (results[handle] = formatAccordingToType(listBigIntDecryptions[idx], typesList[idx])));
|
|
604
611
|
return results;
|
|
605
612
|
}
|
|
@@ -705,7 +712,7 @@ const userDecryptRequest = (kmsSigners, gatewayChainId, chainId, verifyingContra
|
|
|
705
712
|
};
|
|
706
713
|
const decryption = TKMS.process_user_decryption_resp_from_js(client, payloadForVerification, eip712Domain, json.response, pubKey, privKey, true);
|
|
707
714
|
const listBigIntDecryptions = decryption.map((d) => bytesToBigInt(d.bytes));
|
|
708
|
-
const results =
|
|
715
|
+
const results = buildUserDecryptResults(handles.map((h) => h.handle), listBigIntDecryptions);
|
|
709
716
|
return results;
|
|
710
717
|
}
|
|
711
718
|
catch (e) {
|
|
@@ -1116,6 +1123,74 @@ function isThresholdReached(kmsSigners, recoveredAddresses, threshold) {
|
|
|
1116
1123
|
}
|
|
1117
1124
|
return recoveredAddresses.length >= threshold;
|
|
1118
1125
|
}
|
|
1126
|
+
function abiEncodeClearValues(clearValues) {
|
|
1127
|
+
const handlesBytes32Hex = Object.keys(clearValues);
|
|
1128
|
+
const abiTypes = [];
|
|
1129
|
+
const abiValues = [];
|
|
1130
|
+
for (let i = 0; i < handlesBytes32Hex.length; ++i) {
|
|
1131
|
+
const handle = handlesBytes32Hex[i];
|
|
1132
|
+
const handleType = getHandleType(handle);
|
|
1133
|
+
let clearTextValue = clearValues[handle];
|
|
1134
|
+
if (typeof clearTextValue === 'boolean') {
|
|
1135
|
+
clearTextValue = clearTextValue ? '0x01' : '0x00';
|
|
1136
|
+
}
|
|
1137
|
+
const clearTextValueBigInt = BigInt(clearTextValue);
|
|
1138
|
+
//abiTypes.push(fhevmTypeInfo.solidityTypeName);
|
|
1139
|
+
abiTypes.push('uint256');
|
|
1140
|
+
switch (handleType) {
|
|
1141
|
+
// eaddress
|
|
1142
|
+
case 7: {
|
|
1143
|
+
// string
|
|
1144
|
+
abiValues.push(`0x${clearTextValueBigInt.toString(16).padStart(40, '0')}`);
|
|
1145
|
+
break;
|
|
1146
|
+
}
|
|
1147
|
+
// ebool
|
|
1148
|
+
case 0: {
|
|
1149
|
+
// bigint (0 or 1)
|
|
1150
|
+
if (clearTextValueBigInt !== BigInt(0) &&
|
|
1151
|
+
clearTextValueBigInt !== BigInt(1)) {
|
|
1152
|
+
throw new Error(`Invalid ebool clear text value ${clearTextValueBigInt}. Expecting 0 or 1.`);
|
|
1153
|
+
}
|
|
1154
|
+
abiValues.push(clearTextValueBigInt);
|
|
1155
|
+
break;
|
|
1156
|
+
}
|
|
1157
|
+
case 2: //euint8
|
|
1158
|
+
case 3: //euint16
|
|
1159
|
+
case 4: //euint32
|
|
1160
|
+
case 5: //euint64
|
|
1161
|
+
case 6: //euint128
|
|
1162
|
+
case 7: {
|
|
1163
|
+
//euint256
|
|
1164
|
+
// bigint
|
|
1165
|
+
abiValues.push(clearTextValueBigInt);
|
|
1166
|
+
break;
|
|
1167
|
+
}
|
|
1168
|
+
default: {
|
|
1169
|
+
throw new Error(`Unsupported Fhevm primitive type id: ${handleType}`);
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
const abiCoder = ethers.AbiCoder.defaultAbiCoder();
|
|
1174
|
+
// ABI encode the decryptedResult as done in the KMS, since all decrypted values
|
|
1175
|
+
// are native static types, thay have same abi-encoding as uint256:
|
|
1176
|
+
const abiEncodedClearValues = abiCoder.encode(abiTypes, abiValues);
|
|
1177
|
+
return {
|
|
1178
|
+
abiTypes,
|
|
1179
|
+
abiValues,
|
|
1180
|
+
abiEncodedClearValues,
|
|
1181
|
+
};
|
|
1182
|
+
}
|
|
1183
|
+
function buildDecryptionProof(kmsSignatures, extraData) {
|
|
1184
|
+
// Build the decryptionProof as numSigners + KMS signatures + extraData
|
|
1185
|
+
const packedNumSigners = ethers.solidityPacked(['uint8'], [kmsSignatures.length]);
|
|
1186
|
+
const packedSignatures = ethers.solidityPacked(Array(kmsSignatures.length).fill('bytes'), kmsSignatures);
|
|
1187
|
+
const decryptionProof = ethers.concat([
|
|
1188
|
+
packedNumSigners,
|
|
1189
|
+
packedSignatures,
|
|
1190
|
+
extraData,
|
|
1191
|
+
]);
|
|
1192
|
+
return decryptionProof;
|
|
1193
|
+
}
|
|
1119
1194
|
const CiphertextType = {
|
|
1120
1195
|
0: 'bool',
|
|
1121
1196
|
2: 'uint256',
|
|
@@ -1126,7 +1201,7 @@ const CiphertextType = {
|
|
|
1126
1201
|
7: 'address',
|
|
1127
1202
|
8: 'uint256',
|
|
1128
1203
|
};
|
|
1129
|
-
function
|
|
1204
|
+
function deserializeClearValues(handles, decryptedResult) {
|
|
1130
1205
|
let typesList = [];
|
|
1131
1206
|
for (const handle of handles) {
|
|
1132
1207
|
const hexPair = handle.slice(-4, -2).toLowerCase();
|
|
@@ -1145,7 +1220,7 @@ function deserializeDecryptedResult(handles, decryptedResult) {
|
|
|
1145
1220
|
const decoded = coder.decode(['uint256', ...abiTypes, 'bytes[]'], restoredEncoded);
|
|
1146
1221
|
// strip dummy first/last element
|
|
1147
1222
|
const rawValues = decoded.slice(1, 1 + typesList.length);
|
|
1148
|
-
|
|
1223
|
+
const results = {};
|
|
1149
1224
|
handles.forEach((handle, idx) => (results[handle] = rawValues[idx]));
|
|
1150
1225
|
return results;
|
|
1151
1226
|
}
|
|
@@ -1190,22 +1265,25 @@ const publicDecryptRequest = (kmsSigners, thresholdSigners, gatewayChainId, veri
|
|
|
1190
1265
|
],
|
|
1191
1266
|
};
|
|
1192
1267
|
const result = json.response[0];
|
|
1193
|
-
const decryptedResult = result.decrypted_value
|
|
1194
|
-
|
|
1195
|
-
: `0x${result.decrypted_value}`;
|
|
1196
|
-
const signatures = result.signatures;
|
|
1268
|
+
const decryptedResult = ensure0x(result.decrypted_value);
|
|
1269
|
+
const kmsSignatures = result.signatures.map(ensure0x);
|
|
1197
1270
|
const signedExtraData = '0x';
|
|
1198
|
-
const recoveredAddresses =
|
|
1199
|
-
const
|
|
1200
|
-
const recoveredAddress = ethers.verifyTypedData(domain, types, { ctHandles: handles, decryptedResult, extraData: signedExtraData }, sig);
|
|
1271
|
+
const recoveredAddresses = kmsSignatures.map((kmsSignature) => {
|
|
1272
|
+
const recoveredAddress = ethers.verifyTypedData(domain, types, { ctHandles: handles, decryptedResult, extraData: signedExtraData }, kmsSignature);
|
|
1201
1273
|
return recoveredAddress;
|
|
1202
1274
|
});
|
|
1203
1275
|
const thresholdReached = isThresholdReached(kmsSigners, recoveredAddresses, thresholdSigners);
|
|
1204
1276
|
if (!thresholdReached) {
|
|
1205
1277
|
throw Error('KMS signers threshold is not reached');
|
|
1206
1278
|
}
|
|
1207
|
-
const
|
|
1208
|
-
|
|
1279
|
+
const clearValues = deserializeClearValues(handles, decryptedResult);
|
|
1280
|
+
const abiEnc = abiEncodeClearValues(clearValues);
|
|
1281
|
+
const decryptionProof = buildDecryptionProof(kmsSignatures, signedExtraData);
|
|
1282
|
+
return {
|
|
1283
|
+
clearValues,
|
|
1284
|
+
abiEncodedClearValues: abiEnc.abiEncodedClearValues,
|
|
1285
|
+
decryptionProof,
|
|
1286
|
+
};
|
|
1209
1287
|
};
|
|
1210
1288
|
|
|
1211
1289
|
/**
|
|
@@ -1315,23 +1393,23 @@ const generateKeypair = () => {
|
|
|
1315
1393
|
global.fetch = fetchRetry(global.fetch, { retries: 5, retryDelay: 500 });
|
|
1316
1394
|
const SepoliaConfig = {
|
|
1317
1395
|
// ACL_CONTRACT_ADDRESS (FHEVM Host chain)
|
|
1318
|
-
aclContractAddress: '
|
|
1396
|
+
aclContractAddress: '0xf0Ffdc93b7E186bC2f8CB3dAA75D86d1930A433D',
|
|
1319
1397
|
// KMS_VERIFIER_CONTRACT_ADDRESS (FHEVM Host chain)
|
|
1320
|
-
kmsContractAddress: '
|
|
1398
|
+
kmsContractAddress: '0xbE0E383937d564D7FF0BC3b46c51f0bF8d5C311A',
|
|
1321
1399
|
// INPUT_VERIFIER_CONTRACT_ADDRESS (FHEVM Host chain)
|
|
1322
|
-
inputVerifierContractAddress: '
|
|
1400
|
+
inputVerifierContractAddress: '0xBBC1fFCdc7C316aAAd72E807D9b0272BE8F84DA0',
|
|
1323
1401
|
// DECRYPTION_ADDRESS (Gateway chain)
|
|
1324
|
-
verifyingContractAddressDecryption: '
|
|
1402
|
+
verifyingContractAddressDecryption: '0x5D8BD78e2ea6bbE41f26dFe9fdaEAa349e077478',
|
|
1325
1403
|
// INPUT_VERIFICATION_ADDRESS (Gateway chain)
|
|
1326
|
-
verifyingContractAddressInputVerification: '
|
|
1404
|
+
verifyingContractAddressInputVerification: '0x483b9dE06E4E4C7D35CCf5837A1668487406D955',
|
|
1327
1405
|
// FHEVM Host chain id
|
|
1328
1406
|
chainId: 11155111,
|
|
1329
1407
|
// Gateway chain id
|
|
1330
|
-
gatewayChainId:
|
|
1408
|
+
gatewayChainId: 10901,
|
|
1331
1409
|
// Optional RPC provider to host chain
|
|
1332
1410
|
network: 'https://eth-sepolia.public.blastapi.io',
|
|
1333
1411
|
// Relayer URL
|
|
1334
|
-
relayerUrl: 'https://relayer.testnet.zama.
|
|
1412
|
+
relayerUrl: 'https://relayer.testnet.zama.org',
|
|
1335
1413
|
};
|
|
1336
1414
|
const createInstance = async (config) => {
|
|
1337
1415
|
const { verifyingContractAddressDecryption, verifyingContractAddressInputVerification, publicKey, kmsContractAddress, aclContractAddress, gatewayChainId, auth, } = config;
|
package/lib/web.d.ts
CHANGED
|
@@ -52,6 +52,10 @@ declare type BearerToken = {
|
|
|
52
52
|
token: string;
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
+
export declare type ClearValues = Record<`0x${string}`, ClearValueType>;
|
|
56
|
+
|
|
57
|
+
export declare type ClearValueType = bigint | boolean | `0x${string}`;
|
|
58
|
+
|
|
55
59
|
/**
|
|
56
60
|
* Creates an EIP712 structure specifically for user decrypt requests
|
|
57
61
|
*
|
|
@@ -69,8 +73,6 @@ export declare const createEIP712: (verifyingContract: string, contractsChainId:
|
|
|
69
73
|
|
|
70
74
|
export declare const createInstance: (config: FhevmInstanceConfig) => Promise<FhevmInstance>;
|
|
71
75
|
|
|
72
|
-
export declare type DecryptedResults = Record<string, bigint | boolean | string>;
|
|
73
|
-
|
|
74
76
|
export declare type EIP712 = {
|
|
75
77
|
domain: {
|
|
76
78
|
chainId: number;
|
|
@@ -113,8 +115,8 @@ export declare type FhevmInstance = {
|
|
|
113
115
|
privateKey: string;
|
|
114
116
|
};
|
|
115
117
|
createEIP712: (publicKey: string, contractAddresses: string[], startTimestamp: string | number, durationDays: string | number) => EIP712;
|
|
116
|
-
publicDecrypt: (handles: (string | Uint8Array)[]) => Promise<
|
|
117
|
-
userDecrypt: (handles: HandleContractPair[], privateKey: string, publicKey: string, signature: string, contractAddresses: string[], userAddress: string, startTimestamp: string | number, durationDays: string | number) => Promise<
|
|
118
|
+
publicDecrypt: (handles: (string | Uint8Array)[]) => Promise<PublicDecryptResults>;
|
|
119
|
+
userDecrypt: (handles: HandleContractPair[], privateKey: string, publicKey: string, signature: string, contractAddresses: string[], userAddress: string, startTimestamp: string | number, durationDays: string | number) => Promise<UserDecryptResults>;
|
|
118
120
|
getPublicKey: () => {
|
|
119
121
|
publicKeyId: string;
|
|
120
122
|
publicKey: Uint8Array;
|
|
@@ -165,6 +167,12 @@ export declare const initSDK: ({ tfheParams, kmsParams, thread, }?: {
|
|
|
165
167
|
|
|
166
168
|
export { KMSInput }
|
|
167
169
|
|
|
170
|
+
export declare type PublicDecryptResults = {
|
|
171
|
+
clearValues: ClearValues;
|
|
172
|
+
abiEncodedClearValues: `0x${string}`;
|
|
173
|
+
decryptionProof: `0x${string}`;
|
|
174
|
+
};
|
|
175
|
+
|
|
168
176
|
export declare type PublicParams<T = TFHEType['CompactPkeCrs']> = {
|
|
169
177
|
[key in EncryptionTypes]?: {
|
|
170
178
|
publicParams: T;
|
|
@@ -205,4 +213,6 @@ declare type TFHEType = {
|
|
|
205
213
|
ZkComputeLoad: any;
|
|
206
214
|
};
|
|
207
215
|
|
|
216
|
+
export declare type UserDecryptResults = ClearValues;
|
|
217
|
+
|
|
208
218
|
export { }
|