Skip to content

Commit 3d9d160

Browse files
antoniupopisaacdecoded
authored andcommitted
fix(host-contracts): add domain separator and prev block hash to handle hashing (#2014)
* fix(host-contracts): add missing domain separator when hashing to construct handles * fix(host-contracts): update rust bindings * feat(host-contracts): add previous block hash to the hashes used to generate computed handles
1 parent 207fdf0 commit 3d9d160

File tree

3 files changed

+28
-22
lines changed

3 files changed

+28
-22
lines changed

host-contracts/contracts/FHEVMExecutor.sol

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,10 @@ contract FHEVMExecutor is UUPSUpgradeableEmptyProxy, FHEEvents, ACLOwnable {
140140
/// identical between `initializeFromEmptyProxy` and the `reinitializeVX` method
141141
uint64 private constant REINITIALIZER_VERSION = 3;
142142

143+
/// Domain separator for hashing when building an output handle for a FHE computation
144+
bytes8 private constant COMPUTATION_DOMAIN_SEPARATOR = "FHE_comp";
145+
bytes8 private constant SEED_DOMAIN_SEPARATOR = "FHE_seed";
146+
143147
/// keccak256(abi.encode(uint256(keccak256("fhevm.storage.FHEVMExecutor")) - 1)) & ~bytes32(uint256(0xff))
144148
bytes32 private constant FHEVMExecutorStorageLocation =
145149
0x4613e1771f6b755d243e536fb5a23c5b15e2826575fee921e8fe7a22a760c800;
@@ -671,7 +675,7 @@ contract FHEVMExecutor is UUPSUpgradeableEmptyProxy, FHEEvents, ACLOwnable {
671675

672676
/// @dev It must not cast to same type.
673677
if (typeCt == toType) revert InvalidType();
674-
result = keccak256(abi.encodePacked(Operators.cast, ct, toType, acl, block.chainid));
678+
result = keccak256(abi.encodePacked(COMPUTATION_DOMAIN_SEPARATOR, Operators.cast, ct, toType, acl, block.chainid, blockhash(block.number - 1), block.timestamp));
675679
result = _appendMetadataToPrehandle(result, toType);
676680
hcuLimit.checkHCUForCast(toType, ct, result, msg.sender);
677681
acl.allowTransient(result, msg.sender);
@@ -695,7 +699,7 @@ contract FHEVMExecutor is UUPSUpgradeableEmptyProxy, FHEEvents, ACLOwnable {
695699
(1 << uint8(FheType.Uint256));
696700

697701
if ((1 << uint8(toType)) & supportedTypes == 0) revert UnsupportedType();
698-
result = keccak256(abi.encodePacked(Operators.trivialEncrypt, pt, toType, acl, block.chainid));
702+
result = keccak256(abi.encodePacked(COMPUTATION_DOMAIN_SEPARATOR, Operators.trivialEncrypt, pt, toType, acl, block.chainid, blockhash(block.number - 1), block.timestamp));
699703
result = _appendMetadataToPrehandle(result, toType);
700704
hcuLimit.checkHCUForTrivialEncrypt(toType, result, msg.sender);
701705
acl.allowTransient(result, msg.sender);
@@ -812,7 +816,7 @@ contract FHEVMExecutor is UUPSUpgradeableEmptyProxy, FHEEvents, ACLOwnable {
812816

813817
function _unaryOp(Operators op, bytes32 ct) internal virtual returns (bytes32 result) {
814818
if (!acl.isAllowed(ct, msg.sender)) revert ACLNotAllowed(ct, msg.sender);
815-
result = keccak256(abi.encodePacked(op, ct, acl, block.chainid));
819+
result = keccak256(abi.encodePacked(COMPUTATION_DOMAIN_SEPARATOR, op, ct, acl, block.chainid, blockhash(block.number - 1), block.timestamp));
816820
FheType typeCt = _typeOf(ct);
817821
result = _appendMetadataToPrehandle(result, typeCt);
818822
acl.allowTransient(result, msg.sender);
@@ -836,7 +840,7 @@ contract FHEVMExecutor is UUPSUpgradeableEmptyProxy, FHEEvents, ACLOwnable {
836840
FheType lhsType = _typeOf(lhs);
837841
if (lhsType != rhsType) revert IncompatibleTypes();
838842
}
839-
result = keccak256(abi.encodePacked(op, lhs, rhs, scalar, acl, block.chainid));
843+
result = keccak256(abi.encodePacked(COMPUTATION_DOMAIN_SEPARATOR, op, lhs, rhs, scalar, acl, block.chainid, blockhash(block.number - 1), block.timestamp));
840844
result = _appendMetadataToPrehandle(result, resultType);
841845
acl.allowTransient(result, msg.sender);
842846
}
@@ -859,15 +863,15 @@ contract FHEVMExecutor is UUPSUpgradeableEmptyProxy, FHEEvents, ACLOwnable {
859863
if (lhsType != FheType.Bool) revert UnsupportedType();
860864
if (middleType != rhsType) revert IncompatibleTypes();
861865

862-
result = keccak256(abi.encodePacked(op, lhs, middle, rhs, acl, block.chainid));
866+
result = keccak256(abi.encodePacked(COMPUTATION_DOMAIN_SEPARATOR, op, lhs, middle, rhs, acl, block.chainid, blockhash(block.number - 1), block.timestamp));
863867
result = _appendMetadataToPrehandle(result, middleType);
864868
acl.allowTransient(result, msg.sender);
865869
}
866870

867871
function _generateSeed() internal virtual returns (bytes16 seed) {
868872
FHEVMExecutorStorage storage $ = _getFHEVMExecutorStorage();
869873
seed = bytes16(
870-
keccak256(abi.encodePacked($.counterRand, acl, block.chainid, blockhash(block.number - 1), block.timestamp))
874+
keccak256(abi.encodePacked(SEED_DOMAIN_SEPARATOR, $.counterRand, acl, block.chainid, blockhash(block.number - 1), block.timestamp))
871875
);
872876
$.counterRand++;
873877
}
@@ -883,7 +887,7 @@ contract FHEVMExecutor is UUPSUpgradeableEmptyProxy, FHEEvents, ACLOwnable {
883887

884888
/// @dev Unsupported erandom type.
885889
if ((1 << uint8(randType)) & supportedTypes == 0) revert UnsupportedType();
886-
result = keccak256(abi.encodePacked(Operators.fheRand, randType, seed));
890+
result = keccak256(abi.encodePacked(COMPUTATION_DOMAIN_SEPARATOR, Operators.fheRand, randType, seed));
887891
result = _appendMetadataToPrehandle(result, randType);
888892
hcuLimit.checkHCUForFheRand(randType, result, msg.sender);
889893
acl.allowTransient(result, msg.sender);
@@ -904,7 +908,7 @@ contract FHEVMExecutor is UUPSUpgradeableEmptyProxy, FHEEvents, ACLOwnable {
904908
if ((1 << uint8(randType)) & supportedTypes == 0) revert UnsupportedType();
905909
if (!_isPowerOfTwo(upperBound)) revert NotPowerOfTwo();
906910
_checkBelowMaxBound(upperBound, randType);
907-
result = keccak256(abi.encodePacked(Operators.fheRandBounded, upperBound, randType, seed));
911+
result = keccak256(abi.encodePacked(COMPUTATION_DOMAIN_SEPARATOR, Operators.fheRandBounded, upperBound, randType, seed));
908912
result = _appendMetadataToPrehandle(result, randType);
909913
hcuLimit.checkHCUForFheRandBounded(randType, result, msg.sender);
910914
acl.allowTransient(result, msg.sender);

host-contracts/rust_bindings/src/fhevm_executor.rs

Lines changed: 4 additions & 4 deletions
Large diffs are not rendered by default.

host-contracts/test/fhevmExecutor/fhevmExecutor.t.sol

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,8 @@ contract FHEVMExecutorTest is SupportedTypesConstants, Test {
213213
uint256 internal randomCounterForMockHandle;
214214

215215
uint8 internal constant HANDLE_VERSION = 0;
216+
bytes8 internal constant COMPUTATION_DOMAIN_SEPARATOR = "FHE_comp";
217+
bytes8 internal constant SEED_DOMAIN_SEPARATOR = "FHE_seed";
216218
address internal constant owner = address(456);
217219

218220
MockACL internal acl;
@@ -312,7 +314,7 @@ contract FHEVMExecutorTest is SupportedTypesConstants, Test {
312314
bytes32 handle,
313315
FheType resultType
314316
) internal view returns (bytes32 result) {
315-
result = keccak256(abi.encodePacked(op, handle, acl, block.chainid));
317+
result = keccak256(abi.encodePacked(COMPUTATION_DOMAIN_SEPARATOR, op, handle, acl, block.chainid, blockhash(block.number - 1), block.timestamp));
316318
result = _appendMetadataToPrehandle(resultType, result, block.chainid, HANDLE_VERSION);
317319
}
318320

@@ -324,7 +326,7 @@ contract FHEVMExecutorTest is SupportedTypesConstants, Test {
324326
FheType resultType
325327
) internal view returns (bytes32 result) {
326328
scalar = scalar & 0x01;
327-
result = keccak256(abi.encodePacked(op, lhs, rhs, scalar, acl, block.chainid));
329+
result = keccak256(abi.encodePacked(COMPUTATION_DOMAIN_SEPARATOR, op, lhs, rhs, scalar, acl, block.chainid, blockhash(block.number - 1), block.timestamp));
328330
result = _appendMetadataToPrehandle(resultType, result, block.chainid, HANDLE_VERSION);
329331
}
330332

@@ -336,7 +338,7 @@ contract FHEVMExecutorTest is SupportedTypesConstants, Test {
336338
FheType resultType
337339
) internal view returns (bytes32 result) {
338340
scalar = scalar & 0x01;
339-
result = keccak256(abi.encodePacked(op, lhs, rhs, scalar, acl, block.chainid));
341+
result = keccak256(abi.encodePacked(COMPUTATION_DOMAIN_SEPARATOR, op, lhs, rhs, scalar, acl, block.chainid, blockhash(block.number - 1), block.timestamp));
340342
result = _appendMetadataToPrehandle(resultType, result, block.chainid, HANDLE_VERSION);
341343
}
342344

@@ -347,7 +349,7 @@ contract FHEVMExecutorTest is SupportedTypesConstants, Test {
347349
bytes32 rhs,
348350
FheType middleFheType
349351
) internal view returns (bytes32 result) {
350-
result = keccak256(abi.encodePacked(op, lhs, middle, rhs, acl, block.chainid));
352+
result = keccak256(abi.encodePacked(COMPUTATION_DOMAIN_SEPARATOR, op, lhs, middle, rhs, acl, block.chainid, blockhash(block.number - 1), block.timestamp));
351353
result = _appendMetadataToPrehandle(middleFheType, result, block.chainid, HANDLE_VERSION);
352354
}
353355

@@ -1044,12 +1046,12 @@ contract FHEVMExecutorTest is SupportedTypesConstants, Test {
10441046
/// @dev The first argument is the counterRand, which should be 0 for the first call.
10451047
bytes16 expectedSeed = bytes16(
10461048
keccak256(
1047-
abi.encodePacked(uint256(i), acl, block.chainid, blockhash(block.number - 1), block.timestamp)
1049+
abi.encodePacked(SEED_DOMAIN_SEPARATOR, uint256(i), acl, block.chainid, blockhash(block.number - 1), block.timestamp)
10481050
)
10491051
);
10501052

10511053
bytes32 expectedResult = keccak256(
1052-
abi.encodePacked(FHEVMExecutor.Operators.fheRand, FheType(fheType), expectedSeed)
1054+
abi.encodePacked(COMPUTATION_DOMAIN_SEPARATOR, FHEVMExecutor.Operators.fheRand, FheType(fheType), expectedSeed)
10531055
);
10541056

10551057
expectedResult = _appendMetadataToPrehandle(
@@ -1086,12 +1088,12 @@ contract FHEVMExecutorTest is SupportedTypesConstants, Test {
10861088
/// @dev The first argument is the counterRand, which should be 0 for the first call.
10871089
bytes16 expectedSeed = bytes16(
10881090
keccak256(
1089-
abi.encodePacked(uint256(i), acl, block.chainid, blockhash(block.number - 1), block.timestamp)
1091+
abi.encodePacked(SEED_DOMAIN_SEPARATOR, uint256(i), acl, block.chainid, blockhash(block.number - 1), block.timestamp)
10901092
)
10911093
);
10921094

10931095
bytes32 expectedResult = keccak256(
1094-
abi.encodePacked(FHEVMExecutor.Operators.fheRandBounded, upperBound, FheType(fheType), expectedSeed)
1096+
abi.encodePacked(COMPUTATION_DOMAIN_SEPARATOR, FHEVMExecutor.Operators.fheRandBounded, upperBound, FheType(fheType), expectedSeed)
10951097
);
10961098

10971099
expectedResult = _appendMetadataToPrehandle(
@@ -1116,7 +1118,7 @@ contract FHEVMExecutorTest is SupportedTypesConstants, Test {
11161118
address sender = address(123);
11171119

11181120
bytes32 expectedResult = keccak256(
1119-
abi.encodePacked(FHEVMExecutor.Operators.trivialEncrypt, pt, FheType(fheType), acl, block.chainid)
1121+
abi.encodePacked(COMPUTATION_DOMAIN_SEPARATOR, FHEVMExecutor.Operators.trivialEncrypt, pt, FheType(fheType), acl, block.chainid, blockhash(block.number - 1), block.timestamp)
11201122
);
11211123
expectedResult = _appendMetadataToPrehandle(FheType(fheType), expectedResult, block.chainid, HANDLE_VERSION);
11221124

@@ -1142,7 +1144,7 @@ contract FHEVMExecutorTest is SupportedTypesConstants, Test {
11421144
_approveHandleInACL(handle, sender);
11431145

11441146
bytes32 expectedResult = keccak256(
1145-
abi.encodePacked(FHEVMExecutor.Operators.cast, handle, FheType(fheOutputType), acl, block.chainid)
1147+
abi.encodePacked(COMPUTATION_DOMAIN_SEPARATOR, FHEVMExecutor.Operators.cast, handle, FheType(fheOutputType), acl, block.chainid, blockhash(block.number - 1), block.timestamp)
11461148
);
11471149

11481150
expectedResult = _appendMetadataToPrehandle(

0 commit comments

Comments
 (0)