diff --git a/contracts/contracts/ACL.sol b/contracts/contracts/ACL.sol index 8b0c46a3..a5c4ccbe 100644 --- a/contracts/contracts/ACL.sol +++ b/contracts/contracts/ACL.sol @@ -25,8 +25,15 @@ contract ACL is UUPSUpgradeable, Ownable2StepUpgradeable { error SenderNotAllowed(address sender); /// @notice Emitted when a list of handles is allowed for decryption. + /// @param caller account calling the allowForDecryption function. /// @param handlesList List of handles allowed for decryption. - event AllowedForDecryption(uint256[] handlesList); + event AllowedForDecryption(address indexed caller, uint256[] handlesList); + + /// @notice Emitted when a handle is allowed. + /// @param caller account calling the allow function. + /// @param account account being allowed for the handle. + /// @param handle handle being allowed. + event Allowed(address indexed caller, address indexed account, uint256 handle); /// @notice Emitted when a new delegate address is added. /// @param sender Sender address @@ -76,6 +83,7 @@ contract ACL is UUPSUpgradeable, Ownable2StepUpgradeable { revert SenderNotAllowed(msg.sender); } $.persistedAllowedPairs[handle][account] = true; + emit Allowed(msg.sender, account, handle); } /** @@ -92,7 +100,7 @@ contract ACL is UUPSUpgradeable, Ownable2StepUpgradeable { } $.allowedForDecryption[handle] = true; } - emit AllowedForDecryption(handlesList); + emit AllowedForDecryption(msg.sender, handlesList); } /** diff --git a/contracts/contracts/TFHEExecutor.sol b/contracts/contracts/TFHEExecutor.sol index bf3d8590..98630d7a 100644 --- a/contracts/contracts/TFHEExecutor.sol +++ b/contracts/contracts/TFHEExecutor.sol @@ -1,143 +1,53 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear pragma solidity ^0.8.24; -import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; -import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; -import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; - -import {ACL} from "./ACL.sol"; -import {FHEGasLimit} from "./FHEGasLimit.sol"; -import {aclAdd} from "../addresses/ACLAddress.sol"; -import {fheGasLimitAdd} from "../addresses/FHEGasLimitAddress.sol"; -import {inputVerifierAdd} from "../addresses/InputVerifierAddress.sol"; - -/** - * @title IInputVerifier. - */ -interface IInputVerifier { - function verifyCiphertext( - TFHEExecutor.ContextUserInputs memory context, - bytes32 inputHandle, - bytes memory inputProof - ) external returns (uint256); -} +import {TFHEExecutorNoEvents} from "./TFHEExecutorNoEvents.sol"; /** - * @title TFHEExecutor. - * @notice This contract implements symbolic execution on the blockchain and one of its - * main responsibilities is to deterministically generate ciphertext handles. + * @title TFHEExecutor + * @notice This contract inherits TFHEExecutorNoEvents and overrides its functions to emit + * events for all TFHE operations. * @dev This contract is deployed using an UUPS proxy. */ -contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { - /// @notice Returned when the handle is not allowed in the ACL for the account. - /// @param handle Handle. - /// @param account Address of the account. - error ACLNotAllowed(uint256 handle, address account); - - /// @notice Returned when the FHE operator attempts to divide by zero. - error DivisionByZero(); - - /// @notice Returned if two types are not compatible for this operation. - error IncompatibleTypes(); - - /// @notice Returned if the length of the bytes is not as expected. - error InvalidByteLength(uint8 typeOf, uint256 length); - - /// @notice Returned if the type is not the expected one. - error InvalidType(); - - /// @notice Returned if it uses the wrong overloaded function (for functions fheEq/fheNe), - /// which does not handle scalar. - error IsScalar(); - - /// @notice Returned if operation is supported only for a scalar (functions fheDiv/fheRem). - error IsNotScalar(); - - /// @notice Returned if the upper bound for generating randomness is not a power of two. - error NotPowerOfTwo(); - - /// @notice Returned if the second operand is not a scalar (for functions fheEq/fheNe). - error SecondOperandIsNotScalar(); - - /// @notice Returned if the type is not supported for this operation. - error UnsupportedType(); - - /** - * @param aclAddress ACL address. - * @param userAddress Address of the user. - * @param contractAddress Contract address. - */ - struct ContextUserInputs { - address aclAddress; - address userAddress; - address contractAddress; - } - - /// @custom:storage-location erc7201:fhevm.storage.TFHEExecutor - struct TFHEExecutorStorage { - /// @dev Counter used for computing handles of randomness operators. It is also used for OPRF, which is used to - /// generate pseudo-random ciphertexts. - uint256 counterRand; - } - - enum Operators { - fheAdd, - fheSub, - fheMul, - fheDiv, - fheRem, - fheBitAnd, - fheBitOr, - fheBitXor, - fheShl, - fheShr, - fheRotl, - fheRotr, - fheEq, - fheNe, - fheGe, - fheGt, - fheLe, - fheLt, - fheMin, - fheMax, - fheNeg, - fheNot, - verifyCiphertext, - cast, - trivialEncrypt, - fheIfThenElse, - fheRand, - fheRandBounded - } - - /// @notice Handle version. - uint8 public constant HANDLE_VERSION = 0; - - /// @notice Name of the contract. - string private constant CONTRACT_NAME = "TFHEExecutor"; - - /// @notice Major version of the contract. - uint256 private constant MAJOR_VERSION = 0; - - /// @notice Minor version of the contract. - uint256 private constant MINOR_VERSION = 1; - - /// @notice Patch version of the contract. - uint256 private constant PATCH_VERSION = 0; - - /// @notice ACL. - ACL private constant acl = ACL(aclAdd); - - /// @notice FHEGasLimit. - FHEGasLimit private constant fheGasLimit = FHEGasLimit(fheGasLimitAdd); - - /// @notice IInputVerifier. - IInputVerifier private constant inputVerifier = IInputVerifier(inputVerifierAdd); - - /// @dev keccak256(abi.encode(uint256(keccak256("fhevm.storage.TFHEExecutor")) - 1)) & ~bytes32(uint256(0xff)) - bytes32 private constant TFHEExecutorStorageLocation = - 0xa436a06f0efce5ea38c956a21e24202a59b3b746d48a23fb52b4a5bc33fe3e00; +contract TFHEExecutor is TFHEExecutorNoEvents { + event FheAdd(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); + event FheSub(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); + event FheMul(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); + event FheDiv(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); + event FheRem(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); + event FheBitAnd(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); + event FheBitOr(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); + event FheBitXor(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); + event FheShl(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); + event FheShr(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); + event FheRotl(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); + event FheRotr(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); + event FheEq(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); + event FheEqBytes(address indexed caller, uint256 lhs, bytes rhs, bytes1 scalarByte, uint256 result); + event FheNe(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); + event FheNeBytes(address indexed caller, uint256 lhs, bytes rhs, bytes1 scalarByte, uint256 result); + event FheGe(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); + event FheGt(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); + event FheLe(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); + event FheLt(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); + event FheMin(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); + event FheMax(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); + event FheNeg(address indexed caller, uint256 ct, uint256 result); + event FheNot(address indexed caller, uint256 ct, uint256 result); + event VerifyCiphertext( + address indexed caller, + bytes32 inputHandle, + address userAddress, + bytes inputProof, + bytes1 inputType, + uint256 result + ); + event Cast(address indexed caller, uint256 ct, bytes1 toType, uint256 result); + event TrivialEncrypt(address indexed caller, uint256 pt, bytes1 toType, uint256 result); + event TrivialEncryptBytes(address indexed caller, bytes pt, bytes1 toType, uint256 result); + event FheIfThenElse(address indexed caller, uint256 control, uint256 ifTrue, uint256 ifFalse, uint256 result); + event FheRand(address indexed caller, bytes1 randType, bytes16 seed, uint256 result); + event FheRandBounded(address indexed caller, uint256 upperBound, bytes1 randType, bytes16 seed, uint256 result); /// @custom:oz-upgrades-unsafe-allow constructor constructor() { @@ -151,13 +61,9 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param scalarByte Scalar byte. * @return result Result. */ - function fheAdd(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { - uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); - _requireType(lhs, supportedTypes); - uint8 lhsType = _typeOf(lhs); - bytes1 scalar = scalarByte & 0x01; - fheGasLimit.payForFheAdd(lhsType, scalar); - result = _binaryOp(Operators.fheAdd, lhs, rhs, scalar, lhsType); + function fheAdd(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { + result = super.fheAdd(lhs, rhs, scalarByte); + emit FheAdd(msg.sender, lhs, rhs, scalarByte, result); } /** @@ -167,13 +73,9 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param scalarByte Scalar byte. * @return result Result. */ - function fheSub(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { - uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); - _requireType(lhs, supportedTypes); - uint8 lhsType = _typeOf(lhs); - bytes1 scalar = scalarByte & 0x01; - fheGasLimit.payForFheSub(lhsType, scalar); - result = _binaryOp(Operators.fheSub, lhs, rhs, scalar, lhsType); + function fheSub(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { + result = super.fheSub(lhs, rhs, scalarByte); + emit FheSub(msg.sender, lhs, rhs, scalarByte, result); } /** @@ -183,13 +85,9 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param scalarByte Scalar byte. * @return result Result. */ - function fheMul(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { - uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); - _requireType(lhs, supportedTypes); - uint8 lhsType = _typeOf(lhs); - bytes1 scalar = scalarByte & 0x01; - fheGasLimit.payForFheMul(lhsType, scalar); - result = _binaryOp(Operators.fheMul, lhs, rhs, scalar, lhsType); + function fheMul(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { + result = super.fheMul(lhs, rhs, scalarByte); + emit FheMul(msg.sender, lhs, rhs, scalarByte, result); } /** @@ -199,15 +97,9 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param scalarByte Scalar byte. * @return result Result. */ - function fheDiv(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { - if (scalarByte & 0x01 != 0x01) revert IsNotScalar(); - if (rhs == 0) revert DivisionByZero(); - uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); - _requireType(lhs, supportedTypes); - uint8 lhsType = _typeOf(lhs); - bytes1 scalar = scalarByte & 0x01; - fheGasLimit.payForFheDiv(lhsType, scalar); - result = _binaryOp(Operators.fheDiv, lhs, rhs, scalar, lhsType); + function fheDiv(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { + result = super.fheDiv(lhs, rhs, scalarByte); + emit FheDiv(msg.sender, lhs, rhs, scalarByte, result); } /** @@ -217,15 +109,9 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param scalarByte Scalar byte. * @return result Result. */ - function fheRem(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { - if (scalarByte & 0x01 != 0x01) revert IsNotScalar(); - if (rhs == 0) revert DivisionByZero(); - uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); - _requireType(lhs, supportedTypes); - uint8 lhsType = _typeOf(lhs); - bytes1 scalar = scalarByte & 0x01; - fheGasLimit.payForFheRem(lhsType, scalar); - result = _binaryOp(Operators.fheRem, lhs, rhs, scalar, lhsType); + function fheRem(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { + result = super.fheRem(lhs, rhs, scalarByte); + emit FheRem(msg.sender, lhs, rhs, scalarByte, result); } /** @@ -235,13 +121,9 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param scalarByte Scalar byte. * @return result Result. */ - function fheBitAnd(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { - uint256 supportedTypes = (1 << 0) + (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); - _requireType(lhs, supportedTypes); - uint8 lhsType = _typeOf(lhs); - bytes1 scalar = scalarByte & 0x01; - fheGasLimit.payForFheBitAnd(lhsType, scalar); - result = _binaryOp(Operators.fheBitAnd, lhs, rhs, scalar, lhsType); + function fheBitAnd(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { + result = super.fheBitAnd(lhs, rhs, scalarByte); + emit FheBitAnd(msg.sender, lhs, rhs, scalarByte, result); } /** @@ -251,13 +133,9 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param scalarByte Scalar byte. * @return result Result. */ - function fheBitOr(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { - uint256 supportedTypes = (1 << 0) + (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); - _requireType(lhs, supportedTypes); - uint8 lhsType = _typeOf(lhs); - bytes1 scalar = scalarByte & 0x01; - fheGasLimit.payForFheBitOr(lhsType, scalar); - result = _binaryOp(Operators.fheBitOr, lhs, rhs, scalar, lhsType); + function fheBitOr(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { + result = super.fheBitOr(lhs, rhs, scalarByte); + emit FheBitOr(msg.sender, lhs, rhs, scalarByte, result); } /** @@ -267,13 +145,9 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param scalarByte Scalar byte. * @return result Result. */ - function fheBitXor(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { - uint256 supportedTypes = (1 << 0) + (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); - _requireType(lhs, supportedTypes); - uint8 lhsType = _typeOf(lhs); - bytes1 scalar = scalarByte & 0x01; - fheGasLimit.payForFheBitXor(lhsType, scalar); - result = _binaryOp(Operators.fheBitXor, lhs, rhs, scalar, lhsType); + function fheBitXor(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { + result = super.fheBitXor(lhs, rhs, scalarByte); + emit FheBitXor(msg.sender, lhs, rhs, scalarByte, result); } /** @@ -283,13 +157,9 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param scalarByte Scalar byte. * @return result Result. */ - function fheShl(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { - uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); - _requireType(lhs, supportedTypes); - uint8 lhsType = _typeOf(lhs); - bytes1 scalar = scalarByte & 0x01; - fheGasLimit.payForFheShl(lhsType, scalar); - result = _binaryOp(Operators.fheShl, lhs, rhs, scalar, lhsType); + function fheShl(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { + result = super.fheShl(lhs, rhs, scalarByte); + emit FheShl(msg.sender, lhs, rhs, scalarByte, result); } /** @@ -299,13 +169,9 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param scalarByte Scalar byte. * @return result Result. */ - function fheShr(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { - uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); - _requireType(lhs, supportedTypes); - uint8 lhsType = _typeOf(lhs); - bytes1 scalar = scalarByte & 0x01; - fheGasLimit.payForFheShr(lhsType, scalar); - result = _binaryOp(Operators.fheShr, lhs, rhs, scalar, lhsType); + function fheShr(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { + result = super.fheShr(lhs, rhs, scalarByte); + emit FheShr(msg.sender, lhs, rhs, scalarByte, result); } /** @@ -315,13 +181,9 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param scalarByte Scalar byte. * @return result Result. */ - function fheRotl(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { - uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); - _requireType(lhs, supportedTypes); - uint8 lhsType = _typeOf(lhs); - bytes1 scalar = scalarByte & 0x01; - fheGasLimit.payForFheRotl(lhsType, scalar); - result = _binaryOp(Operators.fheRotl, lhs, rhs, scalar, lhsType); + function fheRotl(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { + result = super.fheRotl(lhs, rhs, scalarByte); + emit FheRotl(msg.sender, lhs, rhs, scalarByte, result); } /** @@ -331,13 +193,9 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param scalarByte Scalar byte. * @return result Result. */ - function fheRotr(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { - uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); - _requireType(lhs, supportedTypes); - uint8 lhsType = _typeOf(lhs); - bytes1 scalar = scalarByte & 0x01; - fheGasLimit.payForFheRotr(lhsType, scalar); - result = _binaryOp(Operators.fheRotr, lhs, rhs, scalar, lhsType); + function fheRotr(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { + result = super.fheRotr(lhs, rhs, scalarByte); + emit FheRotr(msg.sender, lhs, rhs, scalarByte, result); } /** @@ -347,26 +205,9 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param scalarByte Scalar byte. * @return result Result. */ - function fheEq(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { - uint256 supportedTypes = (1 << 0) + - (1 << 1) + - (1 << 2) + - (1 << 3) + - (1 << 4) + - (1 << 5) + - (1 << 6) + - (1 << 7) + - (1 << 8) + - (1 << 9) + - (1 << 10) + - (1 << 11); - _requireType(lhs, supportedTypes); - uint8 lhsType = _typeOf(lhs); - bytes1 scalar = scalarByte & 0x01; - if (scalar == 0x01 && lhsType > 8) revert IsScalar(); - - fheGasLimit.payForFheEq(lhsType, scalar); - result = _binaryOp(Operators.fheEq, lhs, rhs, scalar, 0); + function fheEq(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { + result = super.fheEq(lhs, rhs, scalarByte); + emit FheEq(msg.sender, lhs, rhs, scalarByte, result); } /** @@ -376,21 +217,9 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param scalarByte Scalar byte. * @return result Result. */ - function fheEq(uint256 lhs, bytes memory rhs, bytes1 scalarByte) public virtual returns (uint256 result) { - uint256 supportedTypes = (1 << 9) + (1 << 10) + (1 << 11); - _requireType(lhs, supportedTypes); - uint8 lhsType = _typeOf(lhs); - bytes1 scalar = scalarByte & 0x01; - - if (scalar != 0x01) revert SecondOperandIsNotScalar(); - fheGasLimit.payForFheEq(lhsType, scalar); - - if (!acl.isAllowed(lhs, msg.sender)) revert ACLNotAllowed(lhs, msg.sender); - _checkByteLengthForTypeOfAbove8(rhs.length, lhsType); - - result = uint256(keccak256(abi.encodePacked(Operators.fheEq, lhs, rhs, scalar, acl, block.chainid))); - result = _appendType(result, 0); - acl.allowTransient(result, msg.sender); + function fheEq(uint256 lhs, bytes memory rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { + result = super.fheEq(lhs, rhs, scalarByte); + emit FheEqBytes(msg.sender, lhs, rhs, scalarByte, result); } /** @@ -400,27 +229,9 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param scalarByte Scalar byte. * @return result Result. */ - function fheNe(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { - uint256 supportedTypes = (1 << 0) + - (1 << 1) + - (1 << 2) + - (1 << 3) + - (1 << 4) + - (1 << 5) + - (1 << 6) + - (1 << 7) + - (1 << 8) + - (1 << 9) + - (1 << 10) + - (1 << 11); - _requireType(lhs, supportedTypes); - uint8 lhsType = _typeOf(lhs); - bytes1 scalar = scalarByte & 0x01; - - if (scalar == 0x01 && lhsType > 8) revert IsScalar(); - - fheGasLimit.payForFheNe(lhsType, scalar); - result = _binaryOp(Operators.fheNe, lhs, rhs, scalar, 0); + function fheNe(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { + result = super.fheNe(lhs, rhs, scalarByte); + emit FheNe(msg.sender, lhs, rhs, scalarByte, result); } /** @@ -430,19 +241,9 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param scalarByte Scalar byte. * @return result Result. */ - function fheNe(uint256 lhs, bytes memory rhs, bytes1 scalarByte) public virtual returns (uint256 result) { - uint256 supportedTypes = (1 << 9) + (1 << 10) + (1 << 11); - _requireType(lhs, supportedTypes); - uint8 lhsType = _typeOf(lhs); - bytes1 scalar = scalarByte & 0x01; - - if (scalar != 0x01) revert SecondOperandIsNotScalar(); - fheGasLimit.payForFheNe(lhsType, scalar); - if (!acl.isAllowed(lhs, msg.sender)) revert ACLNotAllowed(lhs, msg.sender); - _checkByteLengthForTypeOfAbove8(rhs.length, lhsType); - result = uint256(keccak256(abi.encodePacked(Operators.fheNe, lhs, rhs, scalar, acl, block.chainid))); - result = _appendType(result, 0); - acl.allowTransient(result, msg.sender); + function fheNe(uint256 lhs, bytes memory rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { + result = super.fheNe(lhs, rhs, scalarByte); + emit FheNeBytes(msg.sender, lhs, rhs, scalarByte, result); } /** @@ -452,13 +253,9 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param scalarByte Scalar byte. * @return result Result. */ - function fheGe(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { - uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); - _requireType(lhs, supportedTypes); - uint8 lhsType = _typeOf(lhs); - bytes1 scalar = scalarByte & 0x01; - fheGasLimit.payForFheGe(lhsType, scalar); - result = _binaryOp(Operators.fheGe, lhs, rhs, scalar, 0); + function fheGe(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { + result = super.fheGe(lhs, rhs, scalarByte); + emit FheGe(msg.sender, lhs, rhs, scalarByte, result); } /** @@ -468,13 +265,9 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param scalarByte Scalar byte. * @return result Result. */ - function fheGt(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { - uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); - _requireType(lhs, supportedTypes); - uint8 lhsType = _typeOf(lhs); - bytes1 scalar = scalarByte & 0x01; - fheGasLimit.payForFheGt(lhsType, scalar); - result = _binaryOp(Operators.fheGt, lhs, rhs, scalar, 0); + function fheGt(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { + result = super.fheGt(lhs, rhs, scalarByte); + emit FheGt(msg.sender, lhs, rhs, scalarByte, result); } /** @@ -484,13 +277,9 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param scalarByte Scalar byte. * @return result Result. */ - function fheLe(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { - uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); - _requireType(lhs, supportedTypes); - uint8 lhsType = _typeOf(lhs); - bytes1 scalar = scalarByte & 0x01; - fheGasLimit.payForFheLe(lhsType, scalar); - result = _binaryOp(Operators.fheLe, lhs, rhs, scalar, 0); + function fheLe(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { + result = super.fheLe(lhs, rhs, scalarByte); + emit FheLe(msg.sender, lhs, rhs, scalarByte, result); } /** @@ -500,13 +289,9 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param scalarByte Scalar byte. * @return result Result. */ - function fheLt(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { - uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); - _requireType(lhs, supportedTypes); - uint8 lhsType = _typeOf(lhs); - bytes1 scalar = scalarByte & 0x01; - fheGasLimit.payForFheLt(lhsType, scalar); - result = _binaryOp(Operators.fheLt, lhs, rhs, scalar, 0); + function fheLt(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { + result = super.fheLt(lhs, rhs, scalarByte); + emit FheLt(msg.sender, lhs, rhs, scalarByte, result); } /** @@ -516,13 +301,9 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param scalarByte Scalar byte. * @return result Result. */ - function fheMin(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { - uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); - _requireType(lhs, supportedTypes); - uint8 lhsType = _typeOf(lhs); - bytes1 scalar = scalarByte & 0x01; - fheGasLimit.payForFheMin(lhsType, scalar); - result = _binaryOp(Operators.fheMin, lhs, rhs, scalar, lhsType); + function fheMin(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { + result = super.fheMin(lhs, rhs, scalarByte); + emit FheMin(msg.sender, lhs, rhs, scalarByte, result); } /** @@ -532,13 +313,9 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param scalarByte Scalar byte. * @return result Result. */ - function fheMax(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { - uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); - _requireType(lhs, supportedTypes); - uint8 lhsType = _typeOf(lhs); - bytes1 scalar = scalarByte & 0x01; - fheGasLimit.payForFheMax(lhsType, scalar); - result = _binaryOp(Operators.fheMax, lhs, rhs, scalar, lhsType); + function fheMax(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { + result = super.fheMax(lhs, rhs, scalarByte); + emit FheMax(msg.sender, lhs, rhs, scalarByte, result); } /** @@ -546,12 +323,9 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param ct Ct * @return result Result. */ - function fheNeg(uint256 ct) public virtual returns (uint256 result) { - uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); - _requireType(ct, supportedTypes); - uint8 typeCt = _typeOf(ct); - fheGasLimit.payForFheNeg(typeCt); - result = _unaryOp(Operators.fheNeg, ct); + function fheNeg(uint256 ct) public virtual override returns (uint256 result) { + result = super.fheNeg(ct); + emit FheNeg(msg.sender, ct, result); } /** @@ -559,12 +333,9 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param ct Ct * @return result Result. */ - function fheNot(uint256 ct) public virtual returns (uint256 result) { - uint256 supportedTypes = (1 << 0) + (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); - _requireType(ct, supportedTypes); - uint8 typeCt = _typeOf(ct); - fheGasLimit.payForFheNot(typeCt); - result = _unaryOp(Operators.fheNot, ct); + function fheNot(uint256 ct) public virtual override returns (uint256 result) { + result = super.fheNot(ct); + emit FheNot(msg.sender, ct, result); } /** @@ -574,23 +345,13 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param ifFalse If false. * @return result Result. */ - function fheIfThenElse(uint256 control, uint256 ifTrue, uint256 ifFalse) public virtual returns (uint256 result) { - uint256 supportedTypes = (1 << 0) + - (1 << 1) + - (1 << 2) + - (1 << 3) + - (1 << 4) + - (1 << 5) + - (1 << 6) + - (1 << 7) + - (1 << 8) + - (1 << 9) + - (1 << 10) + - (1 << 11); - _requireType(ifTrue, supportedTypes); - uint8 typeCt = _typeOf(ifTrue); - fheGasLimit.payForIfThenElse(typeCt); - result = _ternaryOp(Operators.fheIfThenElse, control, ifTrue, ifFalse); + function fheIfThenElse( + uint256 control, + uint256 ifTrue, + uint256 ifFalse + ) public virtual override returns (uint256 result) { + result = super.fheIfThenElse(control, ifTrue, ifFalse); + emit FheIfThenElse(msg.sender, control, ifTrue, ifFalse, result); } /** @@ -598,9 +359,10 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param randType Type for the random result. * @return result Result. */ - function fheRand(bytes1 randType) public virtual returns (uint256 result) { + function fheRand(bytes1 randType) public virtual override returns (uint256 result) { bytes16 seed = _generateSeed(); result = _generateRand(randType, seed); + emit FheRand(msg.sender, randType, seed, result); } /** @@ -609,9 +371,10 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param randType Type for the random result. * @return result Result. */ - function fheRandBounded(uint256 upperBound, bytes1 randType) public virtual returns (uint256 result) { + function fheRandBounded(uint256 upperBound, bytes1 randType) public virtual override returns (uint256 result) { bytes16 seed = _generateSeed(); result = _generateRandBounded(upperBound, randType, seed); + emit FheRandBounded(msg.sender, upperBound, randType, seed, result); } /** @@ -620,26 +383,9 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param toType Target type. * @return result Result value of the target type. */ - function cast(uint256 ct, bytes1 toType) public virtual returns (uint256 result) { - if (!acl.isAllowed(ct, msg.sender)) revert ACLNotAllowed(ct, msg.sender); - uint256 supportedTypesInput = (1 << 0) + - (1 << 1) + - (1 << 2) + - (1 << 3) + - (1 << 4) + - (1 << 5) + - (1 << 6) + - (1 << 8); - _requireType(ct, supportedTypesInput); - uint256 supportedTypesOutput = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); // @note: unsupported casting to ebool (use fheNe instead) - if ((1 << uint8(toType)) & supportedTypesOutput == 0) revert UnsupportedType(); - uint8 typeCt = _typeOf(ct); - /// @dev It must not cast to same type. - if (bytes1(typeCt) == toType) revert InvalidType(); - fheGasLimit.payForCast(typeCt); - result = uint256(keccak256(abi.encodePacked(Operators.cast, ct, toType, acl, block.chainid))); - result = _appendType(result, uint8(toType)); - acl.allowTransient(result, msg.sender); + function cast(uint256 ct, bytes1 toType) public virtual override returns (uint256 result) { + result = super.cast(ct, toType); + emit Cast(msg.sender, ct, toType, result); } /** @@ -648,22 +394,9 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @param toType Target type. * @return result Result value of the target type. */ - function trivialEncrypt(uint256 pt, bytes1 toType) public virtual returns (uint256 result) { - uint256 supportedTypes = (1 << 0) + - (1 << 1) + - (1 << 2) + - (1 << 3) + - (1 << 4) + - (1 << 5) + - (1 << 6) + - (1 << 7) + - (1 << 8); - uint8 toT = uint8(toType); - if ((1 << toT) & supportedTypes == 0) revert UnsupportedType(); - fheGasLimit.payForTrivialEncrypt(toT); - result = uint256(keccak256(abi.encodePacked(Operators.trivialEncrypt, pt, toType, acl, block.chainid))); - result = _appendType(result, toT); - acl.allowTransient(result, msg.sender); + function trivialEncrypt(uint256 pt, bytes1 toType) public virtual override returns (uint256 result) { + result = super.trivialEncrypt(pt, toType); + emit TrivialEncrypt(msg.sender, pt, toType, result); } /** @@ -673,15 +406,9 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { * @return result Result value of the target type. * @dev This is an overloaded function for ebytesXX types. */ - function trivialEncrypt(bytes memory pt, bytes1 toType) public virtual returns (uint256 result) { - uint256 supportedTypes = (1 << 9) + (1 << 10) + (1 << 11); - uint8 toT = uint8(toType); - if ((1 << toT) & supportedTypes == 0) revert UnsupportedType(); - fheGasLimit.payForTrivialEncrypt(toT); - _checkByteLengthForTypeOfAbove8(pt.length, toT); - result = uint256(keccak256(abi.encodePacked(Operators.trivialEncrypt, pt, toType, acl, block.chainid))); - result = _appendType(result, toT); - acl.allowTransient(result, msg.sender); + function trivialEncrypt(bytes memory pt, bytes1 toType) public virtual override returns (uint256 result) { + result = super.trivialEncrypt(pt, toType); + emit TrivialEncryptBytes(msg.sender, pt, toType, result); } /** @@ -697,207 +424,8 @@ contract TFHEExecutor is UUPSUpgradeable, Ownable2StepUpgradeable { address userAddress, bytes memory inputProof, bytes1 inputType - ) public virtual returns (uint256 result) { - ContextUserInputs memory contextUserInputs = ContextUserInputs({ - aclAddress: address(acl), - userAddress: userAddress, - contractAddress: msg.sender - }); - uint8 typeCt = _typeOf(uint256(inputHandle)); - if (uint8(inputType) != typeCt) revert InvalidType(); - result = inputVerifier.verifyCiphertext(contextUserInputs, inputHandle, inputProof); - acl.allowTransient(result, msg.sender); - } - - /** - * @notice Getter function for the ACL contract address. - */ - function getACLAddress() public view virtual returns (address) { - return address(acl); - } - - /** - * @notice Getter function for the FHEGasLimit contract address. - */ - function getFHEGasLimitAddress() public view virtual returns (address) { - return address(fheGasLimit); - } - - /** - * @notice Getter function for the InputVerifier contract address. - */ - function getInputVerifierAddress() public view virtual returns (address) { - return address(inputVerifier); - } - - /** - * @notice Getter for the name and version of the contract. - * @return string Name and the version of the contract. - */ - function getVersion() external pure virtual returns (string memory) { - return - string( - abi.encodePacked( - CONTRACT_NAME, - " v", - Strings.toString(MAJOR_VERSION), - ".", - Strings.toString(MINOR_VERSION), - ".", - Strings.toString(PATCH_VERSION) - ) - ); - } - - /** - * @dev Handle format for user inputs is: keccak256(keccak256(CiphertextFHEList)||index_handle)[0:29] || index_handle || handle_type || handle_version - * Other handles format (fhe ops results) is: keccak256(keccak256(rawCiphertextFHEList)||index_handle)[0:30] || handle_type || handle_version - * The CiphertextFHEList actually contains: 1 byte (= N) for size of handles_list, N bytes for the handles_types : 1 per handle, then the original fhe160list raw ciphertext - */ - function _typeOf(uint256 handle) internal pure virtual returns (uint8) { - uint8 typeCt = uint8(handle >> 8); - return typeCt; - } - - function _appendType(uint256 prehandle, uint8 handleType) internal pure virtual returns (uint256 result) { - result = prehandle & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000; - result = result | (uint256(handleType) << 8); /// @dev Appends the type. - result = result | HANDLE_VERSION; + ) public virtual override returns (uint256 result) { + result = super.verifyCiphertext(inputHandle, userAddress, inputProof, inputType); + emit VerifyCiphertext(msg.sender, inputHandle, userAddress, inputProof, inputType, result); } - - /** - * @dev Checks the length for typeOf >= 9. - */ - function _checkByteLengthForTypeOfAbove8(uint256 byteLength, uint8 typeOf) internal pure virtual { - if (typeOf == 9) { - if (byteLength != 64) revert InvalidByteLength(typeOf, byteLength); - } else if (typeOf == 10) { - if (byteLength != 128) revert InvalidByteLength(typeOf, byteLength); - } else { - /// @dev i.e typeOf == 11. - if (byteLength != 256) revert InvalidByteLength(typeOf, byteLength); - } - } - - function _requireType(uint256 handle, uint256 supportedTypes) internal pure virtual { - uint8 typeCt = _typeOf(handle); - if ((1 << typeCt) & supportedTypes == 0) revert UnsupportedType(); - } - - function _unaryOp(Operators op, uint256 ct) internal virtual returns (uint256 result) { - if (!acl.isAllowed(ct, msg.sender)) revert ACLNotAllowed(ct, msg.sender); - result = uint256(keccak256(abi.encodePacked(op, ct, acl, block.chainid))); - uint8 typeCt = _typeOf(ct); - result = _appendType(result, typeCt); - acl.allowTransient(result, msg.sender); - } - - function _binaryOp( - Operators op, - uint256 lhs, - uint256 rhs, - bytes1 scalar, - uint8 resultType - ) internal virtual returns (uint256 result) { - if (!acl.isAllowed(lhs, msg.sender)) revert ACLNotAllowed(lhs, msg.sender); - if (scalar == 0x00) { - if (!acl.isAllowed(rhs, msg.sender)) revert ACLNotAllowed(rhs, msg.sender); - - uint8 typeRhs = _typeOf(rhs); - uint8 typeLhs = _typeOf(lhs); - if (typeLhs != typeRhs) revert IncompatibleTypes(); - } - result = uint256(keccak256(abi.encodePacked(op, lhs, rhs, scalar, acl, block.chainid))); - result = _appendType(result, resultType); - acl.allowTransient(result, msg.sender); - } - - function _ternaryOp( - Operators op, - uint256 lhs, - uint256 middle, - uint256 rhs - ) internal virtual returns (uint256 result) { - if (!acl.isAllowed(lhs, msg.sender)) revert ACLNotAllowed(lhs, msg.sender); - if (!acl.isAllowed(middle, msg.sender)) revert ACLNotAllowed(middle, msg.sender); - if (!acl.isAllowed(rhs, msg.sender)) revert ACLNotAllowed(rhs, msg.sender); - - uint8 typeLhs = _typeOf(lhs); - uint8 typeMiddle = _typeOf(middle); - uint8 typeRhs = _typeOf(rhs); - - if (typeLhs != 0) revert UnsupportedType(); /// @dev lhs must be ebool - if (typeMiddle != typeRhs) revert IncompatibleTypes(); - - result = uint256(keccak256(abi.encodePacked(op, lhs, middle, rhs, acl, block.chainid))); - result = _appendType(result, typeMiddle); - acl.allowTransient(result, msg.sender); - } - - function _generateSeed() internal virtual returns (bytes16 seed) { - TFHEExecutorStorage storage $ = _getTFHEExecutorStorage(); - seed = bytes16( - keccak256(abi.encodePacked($.counterRand, acl, block.chainid, blockhash(block.number - 1), block.timestamp)) - ); - $.counterRand++; - } - - function _generateRand(bytes1 randType, bytes16 seed) internal virtual returns (uint256 result) { - uint256 supportedTypes = (1 << 0) + - (1 << 1) + - (1 << 2) + - (1 << 3) + - (1 << 4) + - (1 << 5) + - (1 << 6) + - (1 << 8) + - (1 << 9) + - (1 << 10) + - (1 << 11); - uint8 randT = uint8(randType); - /// @dev Unsupported erandom type. - if ((1 << randT) & supportedTypes == 0) revert UnsupportedType(); - fheGasLimit.payForFheRand(randT); - result = uint256(keccak256(abi.encodePacked(Operators.fheRand, randType, seed))); - result = _appendType(result, randT); - acl.allowTransient(result, msg.sender); - } - - function _generateRandBounded( - uint256 upperBound, - bytes1 randType, - bytes16 seed - ) internal virtual returns (uint256 result) { - uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); - uint8 randT = uint8(randType); - /// @dev Unsupported erandom type. - if ((1 << randT) & supportedTypes == 0) revert UnsupportedType(); - if (!_isPowerOfTwo(upperBound)) revert NotPowerOfTwo(); - fheGasLimit.payForFheRandBounded(randT); - result = uint256(keccak256(abi.encodePacked(Operators.fheRandBounded, upperBound, randType, seed))); - result = _appendType(result, randT); - acl.allowTransient(result, msg.sender); - } - - /** - * @dev Checks if the value is power of 2. - * @param x Value to check. - */ - function _isPowerOfTwo(uint256 x) internal pure virtual returns (bool) { - return (x > 0) && ((x & (x - 1)) == 0); - } - - /** - * @dev Returns the TFHEExecutor storage location. - */ - function _getTFHEExecutorStorage() internal pure returns (TFHEExecutorStorage storage $) { - assembly { - $.slot := TFHEExecutorStorageLocation - } - } - - /** - * @dev Should revert when `msg.sender` is not authorized to upgrade the contract. - */ - function _authorizeUpgrade(address _newImplementation) internal virtual override onlyOwner {} } diff --git a/contracts/contracts/TFHEExecutorNoEvents.sol b/contracts/contracts/TFHEExecutorNoEvents.sol new file mode 100644 index 00000000..4559faeb --- /dev/null +++ b/contracts/contracts/TFHEExecutorNoEvents.sol @@ -0,0 +1,903 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +pragma solidity ^0.8.24; + +import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; +import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +import {ACL} from "./ACL.sol"; +import {FHEGasLimit} from "./FHEGasLimit.sol"; +import {aclAdd} from "../addresses/ACLAddress.sol"; +import {fheGasLimitAdd} from "../addresses/FHEGasLimitAddress.sol"; +import {inputVerifierAdd} from "../addresses/InputVerifierAddress.sol"; + +/** + * @title IInputVerifier. + */ +interface IInputVerifier { + function verifyCiphertext( + TFHEExecutorNoEvents.ContextUserInputs memory context, + bytes32 inputHandle, + bytes memory inputProof + ) external returns (uint256); +} + +/** + * @title TFHEExecutorNoEvents. + * @notice This contract implements symbolic execution on the blockchain and one of its + * main responsibilities is to deterministically generate ciphertext handles. + * @dev This contract is deployed using an UUPS proxy. + */ +contract TFHEExecutorNoEvents is UUPSUpgradeable, Ownable2StepUpgradeable { + /// @notice Returned when the handle is not allowed in the ACL for the account. + /// @param handle Handle. + /// @param account Address of the account. + error ACLNotAllowed(uint256 handle, address account); + + /// @notice Returned when the FHE operator attempts to divide by zero. + error DivisionByZero(); + + /// @notice Returned if two types are not compatible for this operation. + error IncompatibleTypes(); + + /// @notice Returned if the length of the bytes is not as expected. + error InvalidByteLength(uint8 typeOf, uint256 length); + + /// @notice Returned if the type is not the expected one. + error InvalidType(); + + /// @notice Returned if it uses the wrong overloaded function (for functions fheEq/fheNe), + /// which does not handle scalar. + error IsScalar(); + + /// @notice Returned if operation is supported only for a scalar (functions fheDiv/fheRem). + error IsNotScalar(); + + /// @notice Returned if the upper bound for generating randomness is not a power of two. + error NotPowerOfTwo(); + + /// @notice Returned if the second operand is not a scalar (for functions fheEq/fheNe). + error SecondOperandIsNotScalar(); + + /// @notice Returned if the type is not supported for this operation. + error UnsupportedType(); + + /** + * @param aclAddress ACL address. + * @param userAddress Address of the user. + * @param contractAddress Contract address. + */ + struct ContextUserInputs { + address aclAddress; + address userAddress; + address contractAddress; + } + + /// @custom:storage-location erc7201:fhevm.storage.TFHEExecutor + struct TFHEExecutorStorage { + /// @dev Counter used for computing handles of randomness operators. It is also used for OPRF, which is used to + /// generate pseudo-random ciphertexts. + uint256 counterRand; + } + + enum Operators { + fheAdd, + fheSub, + fheMul, + fheDiv, + fheRem, + fheBitAnd, + fheBitOr, + fheBitXor, + fheShl, + fheShr, + fheRotl, + fheRotr, + fheEq, + fheNe, + fheGe, + fheGt, + fheLe, + fheLt, + fheMin, + fheMax, + fheNeg, + fheNot, + verifyCiphertext, + cast, + trivialEncrypt, + fheIfThenElse, + fheRand, + fheRandBounded + } + + /// @notice Handle version. + uint8 public constant HANDLE_VERSION = 0; + + /// @notice Name of the contract. + string private constant CONTRACT_NAME = "TFHEExecutor"; + + /// @notice Major version of the contract. + uint256 private constant MAJOR_VERSION = 0; + + /// @notice Minor version of the contract. + uint256 private constant MINOR_VERSION = 1; + + /// @notice Patch version of the contract. + uint256 private constant PATCH_VERSION = 0; + + /// @notice ACL. + ACL private constant acl = ACL(aclAdd); + + /// @notice FHEGasLimit. + FHEGasLimit private constant fheGasLimit = FHEGasLimit(fheGasLimitAdd); + + /// @notice IInputVerifier. + IInputVerifier private constant inputVerifier = IInputVerifier(inputVerifierAdd); + + /// @dev keccak256(abi.encode(uint256(keccak256("fhevm.storage.TFHEExecutor")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant TFHEExecutorStorageLocation = + 0xa436a06f0efce5ea38c956a21e24202a59b3b746d48a23fb52b4a5bc33fe3e00; + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + /** + * @notice Computes FHEAdd operation. + * @param lhs LHS. + * @param rhs RHS. + * @param scalarByte Scalar byte. + * @return result Result. + */ + function fheAdd(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { + uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); + _requireType(lhs, supportedTypes); + uint8 lhsType = _typeOf(lhs); + bytes1 scalar = scalarByte & 0x01; + fheGasLimit.payForFheAdd(lhsType, scalar); + result = _binaryOp(Operators.fheAdd, lhs, rhs, scalar, lhsType); + } + + /** + * @notice Computes FHESub operation. + * @param lhs LHS. + * @param rhs RHS. + * @param scalarByte Scalar byte. + * @return result Result. + */ + function fheSub(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { + uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); + _requireType(lhs, supportedTypes); + uint8 lhsType = _typeOf(lhs); + bytes1 scalar = scalarByte & 0x01; + fheGasLimit.payForFheSub(lhsType, scalar); + result = _binaryOp(Operators.fheSub, lhs, rhs, scalar, lhsType); + } + + /** + * @notice Computes FHEMul operation. + * @param lhs LHS. + * @param rhs RHS. + * @param scalarByte Scalar byte. + * @return result Result. + */ + function fheMul(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { + uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); + _requireType(lhs, supportedTypes); + uint8 lhsType = _typeOf(lhs); + bytes1 scalar = scalarByte & 0x01; + fheGasLimit.payForFheMul(lhsType, scalar); + result = _binaryOp(Operators.fheMul, lhs, rhs, scalar, lhsType); + } + + /** + * @notice Computes FHEDiv operation. + * @param lhs LHS. + * @param rhs RHS. + * @param scalarByte Scalar byte. + * @return result Result. + */ + function fheDiv(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { + if (scalarByte & 0x01 != 0x01) revert IsNotScalar(); + if (rhs == 0) revert DivisionByZero(); + uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); + _requireType(lhs, supportedTypes); + uint8 lhsType = _typeOf(lhs); + bytes1 scalar = scalarByte & 0x01; + fheGasLimit.payForFheDiv(lhsType, scalar); + result = _binaryOp(Operators.fheDiv, lhs, rhs, scalar, lhsType); + } + + /** + * @notice Computes FHERem operation. + * @param lhs LHS. + * @param rhs RHS. + * @param scalarByte Scalar byte. + * @return result Result. + */ + function fheRem(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { + if (scalarByte & 0x01 != 0x01) revert IsNotScalar(); + if (rhs == 0) revert DivisionByZero(); + uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); + _requireType(lhs, supportedTypes); + uint8 lhsType = _typeOf(lhs); + bytes1 scalar = scalarByte & 0x01; + fheGasLimit.payForFheRem(lhsType, scalar); + result = _binaryOp(Operators.fheRem, lhs, rhs, scalar, lhsType); + } + + /** + * @notice Computes FHEBitAnd operation. + * @param lhs LHS. + * @param rhs RHS. + * @param scalarByte Scalar byte. + * @return result Result. + */ + function fheBitAnd(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { + uint256 supportedTypes = (1 << 0) + (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); + _requireType(lhs, supportedTypes); + uint8 lhsType = _typeOf(lhs); + bytes1 scalar = scalarByte & 0x01; + fheGasLimit.payForFheBitAnd(lhsType, scalar); + result = _binaryOp(Operators.fheBitAnd, lhs, rhs, scalar, lhsType); + } + + /** + * @notice Computes FHEBitOr operation. + * @param lhs LHS. + * @param rhs RHS. + * @param scalarByte Scalar byte. + * @return result Result. + */ + function fheBitOr(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { + uint256 supportedTypes = (1 << 0) + (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); + _requireType(lhs, supportedTypes); + uint8 lhsType = _typeOf(lhs); + bytes1 scalar = scalarByte & 0x01; + fheGasLimit.payForFheBitOr(lhsType, scalar); + result = _binaryOp(Operators.fheBitOr, lhs, rhs, scalar, lhsType); + } + + /** + * @notice Computes FHEBitXor operation. + * @param lhs LHS. + * @param rhs RHS. + * @param scalarByte Scalar byte. + * @return result Result. + */ + function fheBitXor(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { + uint256 supportedTypes = (1 << 0) + (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); + _requireType(lhs, supportedTypes); + uint8 lhsType = _typeOf(lhs); + bytes1 scalar = scalarByte & 0x01; + fheGasLimit.payForFheBitXor(lhsType, scalar); + result = _binaryOp(Operators.fheBitXor, lhs, rhs, scalar, lhsType); + } + + /** + * @notice Computes FHEShl operation. + * @param lhs LHS. + * @param rhs RHS. + * @param scalarByte Scalar byte. + * @return result Result. + */ + function fheShl(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { + uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); + _requireType(lhs, supportedTypes); + uint8 lhsType = _typeOf(lhs); + bytes1 scalar = scalarByte & 0x01; + fheGasLimit.payForFheShl(lhsType, scalar); + result = _binaryOp(Operators.fheShl, lhs, rhs, scalar, lhsType); + } + + /** + * @notice Computes FHEShr operation. + * @param lhs LHS. + * @param rhs RHS. + * @param scalarByte Scalar byte. + * @return result Result. + */ + function fheShr(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { + uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); + _requireType(lhs, supportedTypes); + uint8 lhsType = _typeOf(lhs); + bytes1 scalar = scalarByte & 0x01; + fheGasLimit.payForFheShr(lhsType, scalar); + result = _binaryOp(Operators.fheShr, lhs, rhs, scalar, lhsType); + } + + /** + * @notice Computes FHERotl operation. + * @param lhs LHS. + * @param rhs RHS. + * @param scalarByte Scalar byte. + * @return result Result. + */ + function fheRotl(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { + uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); + _requireType(lhs, supportedTypes); + uint8 lhsType = _typeOf(lhs); + bytes1 scalar = scalarByte & 0x01; + fheGasLimit.payForFheRotl(lhsType, scalar); + result = _binaryOp(Operators.fheRotl, lhs, rhs, scalar, lhsType); + } + + /** + * @notice Computes FHERotr operation. + * @param lhs LHS. + * @param rhs RHS. + * @param scalarByte Scalar byte. + * @return result Result. + */ + function fheRotr(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { + uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); + _requireType(lhs, supportedTypes); + uint8 lhsType = _typeOf(lhs); + bytes1 scalar = scalarByte & 0x01; + fheGasLimit.payForFheRotr(lhsType, scalar); + result = _binaryOp(Operators.fheRotr, lhs, rhs, scalar, lhsType); + } + + /** + * @notice Computes FHEEq operation. + * @param lhs LHS. + * @param rhs RHS. + * @param scalarByte Scalar byte. + * @return result Result. + */ + function fheEq(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { + uint256 supportedTypes = (1 << 0) + + (1 << 1) + + (1 << 2) + + (1 << 3) + + (1 << 4) + + (1 << 5) + + (1 << 6) + + (1 << 7) + + (1 << 8) + + (1 << 9) + + (1 << 10) + + (1 << 11); + _requireType(lhs, supportedTypes); + uint8 lhsType = _typeOf(lhs); + bytes1 scalar = scalarByte & 0x01; + if (scalar == 0x01 && lhsType > 8) revert IsScalar(); + + fheGasLimit.payForFheEq(lhsType, scalar); + result = _binaryOp(Operators.fheEq, lhs, rhs, scalar, 0); + } + + /** + * @notice Computes FHEEq operation. + * @param lhs LHS. + * @param rhs RHS. + * @param scalarByte Scalar byte. + * @return result Result. + */ + function fheEq(uint256 lhs, bytes memory rhs, bytes1 scalarByte) public virtual returns (uint256 result) { + uint256 supportedTypes = (1 << 9) + (1 << 10) + (1 << 11); + _requireType(lhs, supportedTypes); + uint8 lhsType = _typeOf(lhs); + bytes1 scalar = scalarByte & 0x01; + + if (scalar != 0x01) revert SecondOperandIsNotScalar(); + fheGasLimit.payForFheEq(lhsType, scalar); + + if (!acl.isAllowed(lhs, msg.sender)) revert ACLNotAllowed(lhs, msg.sender); + _checkByteLengthForTypeOfAbove8(rhs.length, lhsType); + + result = uint256(keccak256(abi.encodePacked(Operators.fheEq, lhs, rhs, scalar, acl, block.chainid))); + result = _appendType(result, 0); + acl.allowTransient(result, msg.sender); + } + + /** + * @notice Computes FHENe operation. + * @param lhs LHS. + * @param rhs RHS. + * @param scalarByte Scalar byte. + * @return result Result. + */ + function fheNe(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { + uint256 supportedTypes = (1 << 0) + + (1 << 1) + + (1 << 2) + + (1 << 3) + + (1 << 4) + + (1 << 5) + + (1 << 6) + + (1 << 7) + + (1 << 8) + + (1 << 9) + + (1 << 10) + + (1 << 11); + _requireType(lhs, supportedTypes); + uint8 lhsType = _typeOf(lhs); + bytes1 scalar = scalarByte & 0x01; + + if (scalar == 0x01 && lhsType > 8) revert IsScalar(); + + fheGasLimit.payForFheNe(lhsType, scalar); + result = _binaryOp(Operators.fheNe, lhs, rhs, scalar, 0); + } + + /** + * @notice Computes FHENe operation. + * @param lhs LHS. + * @param rhs RHS. + * @param scalarByte Scalar byte. + * @return result Result. + */ + function fheNe(uint256 lhs, bytes memory rhs, bytes1 scalarByte) public virtual returns (uint256 result) { + uint256 supportedTypes = (1 << 9) + (1 << 10) + (1 << 11); + _requireType(lhs, supportedTypes); + uint8 lhsType = _typeOf(lhs); + bytes1 scalar = scalarByte & 0x01; + + if (scalar != 0x01) revert SecondOperandIsNotScalar(); + fheGasLimit.payForFheNe(lhsType, scalar); + if (!acl.isAllowed(lhs, msg.sender)) revert ACLNotAllowed(lhs, msg.sender); + _checkByteLengthForTypeOfAbove8(rhs.length, lhsType); + result = uint256(keccak256(abi.encodePacked(Operators.fheNe, lhs, rhs, scalar, acl, block.chainid))); + result = _appendType(result, 0); + acl.allowTransient(result, msg.sender); + } + + /** + * @notice Computes FHEGe operation. + * @param lhs LHS. + * @param rhs RHS. + * @param scalarByte Scalar byte. + * @return result Result. + */ + function fheGe(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { + uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); + _requireType(lhs, supportedTypes); + uint8 lhsType = _typeOf(lhs); + bytes1 scalar = scalarByte & 0x01; + fheGasLimit.payForFheGe(lhsType, scalar); + result = _binaryOp(Operators.fheGe, lhs, rhs, scalar, 0); + } + + /** + * @notice Computes FHEGt operation. + * @param lhs LHS. + * @param rhs RHS. + * @param scalarByte Scalar byte. + * @return result Result. + */ + function fheGt(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { + uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); + _requireType(lhs, supportedTypes); + uint8 lhsType = _typeOf(lhs); + bytes1 scalar = scalarByte & 0x01; + fheGasLimit.payForFheGt(lhsType, scalar); + result = _binaryOp(Operators.fheGt, lhs, rhs, scalar, 0); + } + + /** + * @notice Computes FHELe operation. + * @param lhs LHS. + * @param rhs RHS. + * @param scalarByte Scalar byte. + * @return result Result. + */ + function fheLe(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { + uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); + _requireType(lhs, supportedTypes); + uint8 lhsType = _typeOf(lhs); + bytes1 scalar = scalarByte & 0x01; + fheGasLimit.payForFheLe(lhsType, scalar); + result = _binaryOp(Operators.fheLe, lhs, rhs, scalar, 0); + } + + /** + * @notice Computes FHELt operation. + * @param lhs LHS. + * @param rhs RHS. + * @param scalarByte Scalar byte. + * @return result Result. + */ + function fheLt(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { + uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); + _requireType(lhs, supportedTypes); + uint8 lhsType = _typeOf(lhs); + bytes1 scalar = scalarByte & 0x01; + fheGasLimit.payForFheLt(lhsType, scalar); + result = _binaryOp(Operators.fheLt, lhs, rhs, scalar, 0); + } + + /** + * @notice Computes FHEMin operation. + * @param lhs LHS. + * @param rhs RHS. + * @param scalarByte Scalar byte. + * @return result Result. + */ + function fheMin(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { + uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); + _requireType(lhs, supportedTypes); + uint8 lhsType = _typeOf(lhs); + bytes1 scalar = scalarByte & 0x01; + fheGasLimit.payForFheMin(lhsType, scalar); + result = _binaryOp(Operators.fheMin, lhs, rhs, scalar, lhsType); + } + + /** + * @notice Computes FHEMax operation. + * @param lhs LHS. + * @param rhs RHS. + * @param scalarByte Scalar byte. + * @return result Result. + */ + function fheMax(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual returns (uint256 result) { + uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); + _requireType(lhs, supportedTypes); + uint8 lhsType = _typeOf(lhs); + bytes1 scalar = scalarByte & 0x01; + fheGasLimit.payForFheMax(lhsType, scalar); + result = _binaryOp(Operators.fheMax, lhs, rhs, scalar, lhsType); + } + + /** + * @notice Computes FHENeg operation. + * @param ct Ct + * @return result Result. + */ + function fheNeg(uint256 ct) public virtual returns (uint256 result) { + uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); + _requireType(ct, supportedTypes); + uint8 typeCt = _typeOf(ct); + fheGasLimit.payForFheNeg(typeCt); + result = _unaryOp(Operators.fheNeg, ct); + } + + /** + * @notice Computes FHENot operation. + * @param ct Ct + * @return result Result. + */ + function fheNot(uint256 ct) public virtual returns (uint256 result) { + uint256 supportedTypes = (1 << 0) + (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); + _requireType(ct, supportedTypes); + uint8 typeCt = _typeOf(ct); + fheGasLimit.payForFheNot(typeCt); + result = _unaryOp(Operators.fheNot, ct); + } + + /** + * @notice Computes FHEIfThenElse operation. + * @param control Control value. + * @param ifTrue If true. + * @param ifFalse If false. + * @return result Result. + */ + function fheIfThenElse(uint256 control, uint256 ifTrue, uint256 ifFalse) public virtual returns (uint256 result) { + uint256 supportedTypes = (1 << 0) + + (1 << 1) + + (1 << 2) + + (1 << 3) + + (1 << 4) + + (1 << 5) + + (1 << 6) + + (1 << 7) + + (1 << 8) + + (1 << 9) + + (1 << 10) + + (1 << 11); + _requireType(ifTrue, supportedTypes); + uint8 typeCt = _typeOf(ifTrue); + fheGasLimit.payForIfThenElse(typeCt); + result = _ternaryOp(Operators.fheIfThenElse, control, ifTrue, ifFalse); + } + + /** + * @notice Computes FHERand operation. + * @param randType Type for the random result. + * @return result Result. + */ + function fheRand(bytes1 randType) public virtual returns (uint256 result) { + bytes16 seed = _generateSeed(); + result = _generateRand(randType, seed); + } + + /** + * @notice Computes FHERandBounded operation. + * @param upperBound Upper bound value. + * @param randType Type for the random result. + * @return result Result. + */ + function fheRandBounded(uint256 upperBound, bytes1 randType) public virtual returns (uint256 result) { + bytes16 seed = _generateSeed(); + result = _generateRandBounded(upperBound, randType, seed); + } + + /** + * @notice Performs the casting to a target type. + * @param ct Value to cast. + * @param toType Target type. + * @return result Result value of the target type. + */ + function cast(uint256 ct, bytes1 toType) public virtual returns (uint256 result) { + if (!acl.isAllowed(ct, msg.sender)) revert ACLNotAllowed(ct, msg.sender); + uint256 supportedTypesInput = (1 << 0) + + (1 << 1) + + (1 << 2) + + (1 << 3) + + (1 << 4) + + (1 << 5) + + (1 << 6) + + (1 << 8); + _requireType(ct, supportedTypesInput); + uint256 supportedTypesOutput = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); // @note: unsupported casting to ebool (use fheNe instead) + if ((1 << uint8(toType)) & supportedTypesOutput == 0) revert UnsupportedType(); + uint8 typeCt = _typeOf(ct); + /// @dev It must not cast to same type. + if (bytes1(typeCt) == toType) revert InvalidType(); + fheGasLimit.payForCast(typeCt); + result = uint256(keccak256(abi.encodePacked(Operators.cast, ct, toType, acl, block.chainid))); + result = _appendType(result, uint8(toType)); + acl.allowTransient(result, msg.sender); + } + + /** + * @notice Does trivial encryption. + * @param pt Value to encrypt. + * @param toType Target type. + * @return result Result value of the target type. + */ + function trivialEncrypt(uint256 pt, bytes1 toType) public virtual returns (uint256 result) { + uint256 supportedTypes = (1 << 0) + + (1 << 1) + + (1 << 2) + + (1 << 3) + + (1 << 4) + + (1 << 5) + + (1 << 6) + + (1 << 7) + + (1 << 8); + uint8 toT = uint8(toType); + if ((1 << toT) & supportedTypes == 0) revert UnsupportedType(); + fheGasLimit.payForTrivialEncrypt(toT); + result = uint256(keccak256(abi.encodePacked(Operators.trivialEncrypt, pt, toType, acl, block.chainid))); + result = _appendType(result, toT); + acl.allowTransient(result, msg.sender); + } + + /** + * @notice Does trivial encryption. + * @param pt Value to encrypt. + * @param toType Target type. + * @return result Result value of the target type. + * @dev This is an overloaded function for ebytesXX types. + */ + function trivialEncrypt(bytes memory pt, bytes1 toType) public virtual returns (uint256 result) { + uint256 supportedTypes = (1 << 9) + (1 << 10) + (1 << 11); + uint8 toT = uint8(toType); + if ((1 << toT) & supportedTypes == 0) revert UnsupportedType(); + fheGasLimit.payForTrivialEncrypt(toT); + _checkByteLengthForTypeOfAbove8(pt.length, toT); + result = uint256(keccak256(abi.encodePacked(Operators.trivialEncrypt, pt, toType, acl, block.chainid))); + result = _appendType(result, toT); + acl.allowTransient(result, msg.sender); + } + + /** + * @notice Verifies the ciphertext. + * @param inputHandle Input handle. + * @param userAddress Address of the user. + * @param inputProof Input proof. + * @param inputType Input type. + * @return result Result. + */ + function verifyCiphertext( + bytes32 inputHandle, + address userAddress, + bytes memory inputProof, + bytes1 inputType + ) public virtual returns (uint256 result) { + ContextUserInputs memory contextUserInputs = ContextUserInputs({ + aclAddress: address(acl), + userAddress: userAddress, + contractAddress: msg.sender + }); + uint8 typeCt = _typeOf(uint256(inputHandle)); + if (uint8(inputType) != typeCt) revert InvalidType(); + result = inputVerifier.verifyCiphertext(contextUserInputs, inputHandle, inputProof); + acl.allowTransient(result, msg.sender); + } + + /** + * @notice Getter function for the ACL contract address. + */ + function getACLAddress() public view virtual returns (address) { + return address(acl); + } + + /** + * @notice Getter function for the FHEGasLimit contract address. + */ + function getFHEGasLimitAddress() public view virtual returns (address) { + return address(fheGasLimit); + } + + /** + * @notice Getter function for the InputVerifier contract address. + */ + function getInputVerifierAddress() public view virtual returns (address) { + return address(inputVerifier); + } + + /** + * @notice Getter for the name and version of the contract. + * @return string Name and the version of the contract. + */ + function getVersion() external pure virtual returns (string memory) { + return + string( + abi.encodePacked( + CONTRACT_NAME, + " v", + Strings.toString(MAJOR_VERSION), + ".", + Strings.toString(MINOR_VERSION), + ".", + Strings.toString(PATCH_VERSION) + ) + ); + } + + /** + * @dev Handle format for user inputs is: keccak256(keccak256(CiphertextFHEList)||index_handle)[0:29] || index_handle || handle_type || handle_version + * Other handles format (fhe ops results) is: keccak256(keccak256(rawCiphertextFHEList)||index_handle)[0:30] || handle_type || handle_version + * The CiphertextFHEList actually contains: 1 byte (= N) for size of handles_list, N bytes for the handles_types : 1 per handle, then the original fhe160list raw ciphertext + */ + function _typeOf(uint256 handle) internal pure virtual returns (uint8) { + uint8 typeCt = uint8(handle >> 8); + return typeCt; + } + + function _appendType(uint256 prehandle, uint8 handleType) internal pure virtual returns (uint256 result) { + result = prehandle & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000; + result = result | (uint256(handleType) << 8); /// @dev Appends the type. + result = result | HANDLE_VERSION; + } + + /** + * @dev Checks the length for typeOf >= 9. + */ + function _checkByteLengthForTypeOfAbove8(uint256 byteLength, uint8 typeOf) internal pure virtual { + if (typeOf == 9) { + if (byteLength != 64) revert InvalidByteLength(typeOf, byteLength); + } else if (typeOf == 10) { + if (byteLength != 128) revert InvalidByteLength(typeOf, byteLength); + } else { + /// @dev i.e typeOf == 11. + if (byteLength != 256) revert InvalidByteLength(typeOf, byteLength); + } + } + + function _requireType(uint256 handle, uint256 supportedTypes) internal pure virtual { + uint8 typeCt = _typeOf(handle); + if ((1 << typeCt) & supportedTypes == 0) revert UnsupportedType(); + } + + function _unaryOp(Operators op, uint256 ct) internal virtual returns (uint256 result) { + if (!acl.isAllowed(ct, msg.sender)) revert ACLNotAllowed(ct, msg.sender); + result = uint256(keccak256(abi.encodePacked(op, ct, acl, block.chainid))); + uint8 typeCt = _typeOf(ct); + result = _appendType(result, typeCt); + acl.allowTransient(result, msg.sender); + } + + function _binaryOp( + Operators op, + uint256 lhs, + uint256 rhs, + bytes1 scalar, + uint8 resultType + ) internal virtual returns (uint256 result) { + if (!acl.isAllowed(lhs, msg.sender)) revert ACLNotAllowed(lhs, msg.sender); + if (scalar == 0x00) { + if (!acl.isAllowed(rhs, msg.sender)) revert ACLNotAllowed(rhs, msg.sender); + + uint8 typeRhs = _typeOf(rhs); + uint8 typeLhs = _typeOf(lhs); + if (typeLhs != typeRhs) revert IncompatibleTypes(); + } + result = uint256(keccak256(abi.encodePacked(op, lhs, rhs, scalar, acl, block.chainid))); + result = _appendType(result, resultType); + acl.allowTransient(result, msg.sender); + } + + function _ternaryOp( + Operators op, + uint256 lhs, + uint256 middle, + uint256 rhs + ) internal virtual returns (uint256 result) { + if (!acl.isAllowed(lhs, msg.sender)) revert ACLNotAllowed(lhs, msg.sender); + if (!acl.isAllowed(middle, msg.sender)) revert ACLNotAllowed(middle, msg.sender); + if (!acl.isAllowed(rhs, msg.sender)) revert ACLNotAllowed(rhs, msg.sender); + + uint8 typeLhs = _typeOf(lhs); + uint8 typeMiddle = _typeOf(middle); + uint8 typeRhs = _typeOf(rhs); + + if (typeLhs != 0) revert UnsupportedType(); /// @dev lhs must be ebool + if (typeMiddle != typeRhs) revert IncompatibleTypes(); + + result = uint256(keccak256(abi.encodePacked(op, lhs, middle, rhs, acl, block.chainid))); + result = _appendType(result, typeMiddle); + acl.allowTransient(result, msg.sender); + } + + function _generateSeed() internal virtual returns (bytes16 seed) { + TFHEExecutorStorage storage $ = _getTFHEExecutorStorage(); + seed = bytes16( + keccak256(abi.encodePacked($.counterRand, acl, block.chainid, blockhash(block.number - 1), block.timestamp)) + ); + $.counterRand++; + } + + function _generateRand(bytes1 randType, bytes16 seed) internal virtual returns (uint256 result) { + uint256 supportedTypes = (1 << 0) + + (1 << 1) + + (1 << 2) + + (1 << 3) + + (1 << 4) + + (1 << 5) + + (1 << 6) + + (1 << 8) + + (1 << 9) + + (1 << 10) + + (1 << 11); + uint8 randT = uint8(randType); + /// @dev Unsupported erandom type. + if ((1 << randT) & supportedTypes == 0) revert UnsupportedType(); + fheGasLimit.payForFheRand(randT); + result = uint256(keccak256(abi.encodePacked(Operators.fheRand, randType, seed))); + result = _appendType(result, randT); + acl.allowTransient(result, msg.sender); + } + + function _generateRandBounded( + uint256 upperBound, + bytes1 randType, + bytes16 seed + ) internal virtual returns (uint256 result) { + uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 6) + (1 << 8); + uint8 randT = uint8(randType); + /// @dev Unsupported erandom type. + if ((1 << randT) & supportedTypes == 0) revert UnsupportedType(); + if (!_isPowerOfTwo(upperBound)) revert NotPowerOfTwo(); + fheGasLimit.payForFheRandBounded(randT); + result = uint256(keccak256(abi.encodePacked(Operators.fheRandBounded, upperBound, randType, seed))); + result = _appendType(result, randT); + acl.allowTransient(result, msg.sender); + } + + /** + * @dev Checks if the value is power of 2. + * @param x Value to check. + */ + function _isPowerOfTwo(uint256 x) internal pure virtual returns (bool) { + return (x > 0) && ((x & (x - 1)) == 0); + } + + /** + * @dev Returns the TFHEExecutor storage location. + */ + function _getTFHEExecutorStorage() internal pure returns (TFHEExecutorStorage storage $) { + assembly { + $.slot := TFHEExecutorStorageLocation + } + } + + /** + * @dev Should revert when `msg.sender` is not authorized to upgrade the contract. + */ + function _authorizeUpgrade(address _newImplementation) internal virtual override onlyOwner {} +} diff --git a/contracts/contracts/TFHEExecutorWithEvents.sol b/contracts/contracts/TFHEExecutorWithEvents.sol deleted file mode 100644 index 8a872fd7..00000000 --- a/contracts/contracts/TFHEExecutorWithEvents.sol +++ /dev/null @@ -1,430 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause-Clear -pragma solidity ^0.8.24; - -import {TFHEExecutor} from "./TFHEExecutor.sol"; - -/** - * @title TFHEExecutorWithEvents - * @notice This contract inherits TFHEExecutor and overrides its functions to emit - * events for all TFHE operations. - * @dev This contract is deployed using an UUPS proxy. - */ -contract TFHEExecutorWithEvents is TFHEExecutor { - event FheAdd(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); - event FheSub(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); - event FheMul(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); - event FheDiv(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); - event FheRem(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); - event FheBitAnd(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); - event FheBitOr(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); - event FheBitXor(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); - event FheShl(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); - event FheShr(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); - event FheRotl(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); - event FheRotr(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); - event FheEq(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); - event FheEqBytes(uint256 lhs, bytes rhs, bytes1 scalarByte, uint256 result); - event FheNe(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); - event FheNeBytes(uint256 lhs, bytes rhs, bytes1 scalarByte, uint256 result); - event FheGe(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); - event FheGt(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); - event FheLe(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); - event FheLt(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); - event FheMin(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); - event FheMax(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result); - event FheNeg(uint256 ct, uint256 result); - event FheNot(uint256 ct, uint256 result); - event VerifyCiphertext( - bytes32 inputHandle, - address userAddress, - bytes inputProof, - bytes1 inputType, - uint256 result - ); - event Cast(uint256 ct, bytes1 toType, uint256 result); - event TrivialEncrypt(uint256 pt, bytes1 toType, uint256 result); - event TrivialEncryptBytes(bytes pt, bytes1 toType, uint256 result); - event FheIfThenElse(uint256 control, uint256 ifTrue, uint256 ifFalse, uint256 result); - event FheRand(bytes1 randType, bytes16 seed, uint256 result); - event FheRandBounded(uint256 upperBound, bytes1 randType, bytes16 seed, uint256 result); - - /// @custom:oz-upgrades-unsafe-allow constructor - constructor() { - _disableInitializers(); - } - - /** - * @notice Computes FHEAdd operation. - * @param lhs LHS. - * @param rhs RHS. - * @param scalarByte Scalar byte. - * @return result Result. - */ - function fheAdd(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { - result = super.fheAdd(lhs, rhs, scalarByte); - emit FheAdd(lhs, rhs, scalarByte, result); - } - - /** - * @notice Computes FHESub operation. - * @param lhs LHS. - * @param rhs RHS. - * @param scalarByte Scalar byte. - * @return result Result. - */ - function fheSub(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { - result = super.fheSub(lhs, rhs, scalarByte); - emit FheSub(lhs, rhs, scalarByte, result); - } - - /** - * @notice Computes FHEMul operation. - * @param lhs LHS. - * @param rhs RHS. - * @param scalarByte Scalar byte. - * @return result Result. - */ - function fheMul(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { - result = super.fheMul(lhs, rhs, scalarByte); - emit FheMul(lhs, rhs, scalarByte, result); - } - - /** - * @notice Computes FHEDiv operation. - * @param lhs LHS. - * @param rhs RHS. - * @param scalarByte Scalar byte. - * @return result Result. - */ - function fheDiv(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { - result = super.fheDiv(lhs, rhs, scalarByte); - emit FheDiv(lhs, rhs, scalarByte, result); - } - - /** - * @notice Computes FHERem operation. - * @param lhs LHS. - * @param rhs RHS. - * @param scalarByte Scalar byte. - * @return result Result. - */ - function fheRem(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { - result = super.fheRem(lhs, rhs, scalarByte); - emit FheRem(lhs, rhs, scalarByte, result); - } - - /** - * @notice Computes FHEBitAnd operation. - * @param lhs LHS. - * @param rhs RHS. - * @param scalarByte Scalar byte. - * @return result Result. - */ - function fheBitAnd(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { - result = super.fheBitAnd(lhs, rhs, scalarByte); - emit FheBitAnd(lhs, rhs, scalarByte, result); - } - - /** - * @notice Computes FHEBitOr operation. - * @param lhs LHS. - * @param rhs RHS. - * @param scalarByte Scalar byte. - * @return result Result. - */ - function fheBitOr(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { - result = super.fheBitOr(lhs, rhs, scalarByte); - emit FheBitOr(lhs, rhs, scalarByte, result); - } - - /** - * @notice Computes FHEBitXor operation. - * @param lhs LHS. - * @param rhs RHS. - * @param scalarByte Scalar byte. - * @return result Result. - */ - function fheBitXor(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { - result = super.fheBitXor(lhs, rhs, scalarByte); - emit FheBitXor(lhs, rhs, scalarByte, result); - } - - /** - * @notice Computes FHEShl operation. - * @param lhs LHS. - * @param rhs RHS. - * @param scalarByte Scalar byte. - * @return result Result. - */ - function fheShl(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { - result = super.fheShl(lhs, rhs, scalarByte); - emit FheShl(lhs, rhs, scalarByte, result); - } - - /** - * @notice Computes FHEShr operation. - * @param lhs LHS. - * @param rhs RHS. - * @param scalarByte Scalar byte. - * @return result Result. - */ - function fheShr(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { - result = super.fheShr(lhs, rhs, scalarByte); - emit FheShr(lhs, rhs, scalarByte, result); - } - - /** - * @notice Computes FHERotl operation. - * @param lhs LHS. - * @param rhs RHS. - * @param scalarByte Scalar byte. - * @return result Result. - */ - function fheRotl(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { - result = super.fheRotl(lhs, rhs, scalarByte); - emit FheRotl(lhs, rhs, scalarByte, result); - } - - /** - * @notice Computes FHERotr operation. - * @param lhs LHS. - * @param rhs RHS. - * @param scalarByte Scalar byte. - * @return result Result. - */ - function fheRotr(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { - result = super.fheRotr(lhs, rhs, scalarByte); - emit FheRotr(lhs, rhs, scalarByte, result); - } - - /** - * @notice Computes FHEEq operation. - * @param lhs LHS. - * @param rhs RHS. - * @param scalarByte Scalar byte. - * @return result Result. - */ - function fheEq(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { - result = super.fheEq(lhs, rhs, scalarByte); - emit FheEq(lhs, rhs, scalarByte, result); - } - - /** - * @notice Computes FHEEq operation. - * @param lhs LHS. - * @param rhs RHS. - * @param scalarByte Scalar byte. - * @return result Result. - */ - function fheEq(uint256 lhs, bytes memory rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { - result = super.fheEq(lhs, rhs, scalarByte); - emit FheEqBytes(lhs, rhs, scalarByte, result); - } - - /** - * @notice Computes FHENe operation. - * @param lhs LHS. - * @param rhs RHS. - * @param scalarByte Scalar byte. - * @return result Result. - */ - function fheNe(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { - result = super.fheNe(lhs, rhs, scalarByte); - emit FheNe(lhs, rhs, scalarByte, result); - } - - /** - * @notice Computes FHENe operation. - * @param lhs LHS. - * @param rhs RHS. - * @param scalarByte Scalar byte. - * @return result Result. - */ - function fheNe(uint256 lhs, bytes memory rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { - result = super.fheNe(lhs, rhs, scalarByte); - emit FheNeBytes(lhs, rhs, scalarByte, result); - } - - /** - * @notice Computes FHEGe operation. - * @param lhs LHS. - * @param rhs RHS. - * @param scalarByte Scalar byte. - * @return result Result. - */ - function fheGe(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { - result = super.fheGe(lhs, rhs, scalarByte); - emit FheGe(lhs, rhs, scalarByte, result); - } - - /** - * @notice Computes FHEGt operation. - * @param lhs LHS. - * @param rhs RHS. - * @param scalarByte Scalar byte. - * @return result Result. - */ - function fheGt(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { - result = super.fheGt(lhs, rhs, scalarByte); - emit FheGt(lhs, rhs, scalarByte, result); - } - - /** - * @notice Computes FHELe operation. - * @param lhs LHS. - * @param rhs RHS. - * @param scalarByte Scalar byte. - * @return result Result. - */ - function fheLe(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { - result = super.fheLe(lhs, rhs, scalarByte); - emit FheLe(lhs, rhs, scalarByte, result); - } - - /** - * @notice Computes FHELt operation. - * @param lhs LHS. - * @param rhs RHS. - * @param scalarByte Scalar byte. - * @return result Result. - */ - function fheLt(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { - result = super.fheLt(lhs, rhs, scalarByte); - emit FheLt(lhs, rhs, scalarByte, result); - } - - /** - * @notice Computes FHEMin operation. - * @param lhs LHS. - * @param rhs RHS. - * @param scalarByte Scalar byte. - * @return result Result. - */ - function fheMin(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { - result = super.fheMin(lhs, rhs, scalarByte); - emit FheMin(lhs, rhs, scalarByte, result); - } - - /** - * @notice Computes FHEMax operation. - * @param lhs LHS. - * @param rhs RHS. - * @param scalarByte Scalar byte. - * @return result Result. - */ - function fheMax(uint256 lhs, uint256 rhs, bytes1 scalarByte) public virtual override returns (uint256 result) { - result = super.fheMax(lhs, rhs, scalarByte); - emit FheMax(lhs, rhs, scalarByte, result); - } - - /** - * @notice Computes FHENeg operation. - * @param ct Ct - * @return result Result. - */ - function fheNeg(uint256 ct) public virtual override returns (uint256 result) { - result = super.fheNeg(ct); - emit FheNeg(ct, result); - } - - /** - * @notice Computes FHENot operation. - * @param ct Ct - * @return result Result. - */ - function fheNot(uint256 ct) public virtual override returns (uint256 result) { - result = super.fheNot(ct); - emit FheNot(ct, result); - } - - /** - * @notice Computes FHEIfThenElse operation. - * @param control Control value. - * @param ifTrue If true. - * @param ifFalse If false. - * @return result Result. - */ - function fheIfThenElse( - uint256 control, - uint256 ifTrue, - uint256 ifFalse - ) public virtual override returns (uint256 result) { - result = super.fheIfThenElse(control, ifTrue, ifFalse); - emit FheIfThenElse(control, ifTrue, ifFalse, result); - } - - /** - * @notice Computes FHERand operation. - * @param randType Type for the random result. - * @return result Result. - */ - function fheRand(bytes1 randType) public virtual override returns (uint256 result) { - bytes16 seed = _generateSeed(); - result = _generateRand(randType, seed); - emit FheRand(randType, seed, result); - } - - /** - * @notice Computes FHERandBounded operation. - * @param upperBound Upper bound value. - * @param randType Type for the random result. - * @return result Result. - */ - function fheRandBounded(uint256 upperBound, bytes1 randType) public virtual override returns (uint256 result) { - bytes16 seed = _generateSeed(); - result = _generateRandBounded(upperBound, randType, seed); - emit FheRandBounded(upperBound, randType, seed, result); - } - - /** - * @notice Performs the casting to a target type. - * @param ct Value to cast. - * @param toType Target type. - * @return result Result value of the target type. - */ - function cast(uint256 ct, bytes1 toType) public virtual override returns (uint256 result) { - result = super.cast(ct, toType); - emit Cast(ct, toType, result); - } - - /** - * @notice Does trivial encryption. - * @param pt Value to encrypt. - * @param toType Target type. - * @return result Result value of the target type. - */ - function trivialEncrypt(uint256 pt, bytes1 toType) public virtual override returns (uint256 result) { - result = super.trivialEncrypt(pt, toType); - emit TrivialEncrypt(pt, toType, result); - } - - /** - * @notice Does trivial encryption. - * @param pt Value to encrypt. - * @param toType Target type. - * @return result Result value of the target type. - * @dev This is an overloaded function for ebytesXX types. - */ - function trivialEncrypt(bytes memory pt, bytes1 toType) public virtual override returns (uint256 result) { - result = super.trivialEncrypt(pt, toType); - emit TrivialEncryptBytes(pt, toType, result); - } - - /** - * @notice Verifies the ciphertext. - * @param inputHandle Input handle. - * @param userAddress Address of the user. - * @param inputProof Input proof. - * @param inputType Input type. - * @return result Result. - */ - function verifyCiphertext( - bytes32 inputHandle, - address userAddress, - bytes memory inputProof, - bytes1 inputType - ) public virtual override returns (uint256 result) { - result = super.verifyCiphertext(inputHandle, userAddress, inputProof, inputType); - emit VerifyCiphertext(inputHandle, userAddress, inputProof, inputType, result); - } -} diff --git a/contracts/package.json b/contracts/package.json index c53f7b13..cb68944a 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -16,10 +16,8 @@ "prettier": "prettier --write \"**/*.{js,json,md,sol,ts,yml}\"", "test:inband": "hardhat test", "test": "HARDHAT_PARALLEL=1 hardhat test --parallel", - "test:mock": "HARDHAT_TFHEEXECUTOR_EVENTS=1 hardhat test --network hardhat", - "test:mock:original": "hardhat test --network hardhat", - "coverage:mock": "HARDHAT_TFHEEXECUTOR_EVENTS=1 hardhat coverage", - "coverage:mock:original": "hardhat coverage", + "test:mock": "hardhat test --network hardhat", + "coverage:mock": "hardhat coverage", "codegen": "npx ts-node codegen/main.ts && npm run prettier" }, "author": "", diff --git a/contracts/tasks/taskDeploy.ts b/contracts/tasks/taskDeploy.ts index 4edc9754..e04268ff 100644 --- a/contracts/tasks/taskDeploy.ts +++ b/contracts/tasks/taskDeploy.ts @@ -94,15 +94,7 @@ task('task:deployTFHEExecutor') .setAction(async function (taskArguments: TaskArguments, { ethers, upgrades }) { const deployer = new ethers.Wallet(taskArguments.privateKey).connect(ethers.provider); const currentImplementation = await ethers.getContractFactory('EmptyUUPSProxy', deployer); - let newImplem; - if (process.env.HARDHAT_TFHEEXECUTOR_EVENTS !== '1') { - newImplem = await ethers.getContractFactory('./contracts/TFHEExecutor.sol:TFHEExecutor', deployer); - } else { - newImplem = await ethers.getContractFactory( - './contracts/TFHEExecutorWithEvents.sol:TFHEExecutorWithEvents', - deployer, - ); - } + const newImplem = await ethers.getContractFactory('./contracts/TFHEExecutor.sol:TFHEExecutor', deployer); const parsedEnv = dotenv.parse(fs.readFileSync('addresses/.env.exec')); const proxyAddress = parsedEnv.TFHE_EXECUTOR_CONTRACT_ADDRESS; const proxy = await upgrades.forceImport(proxyAddress, currentImplementation); diff --git a/contracts/test/acl/acl.t.sol b/contracts/test/acl/acl.t.sol index 5096b4b5..dc753b15 100644 --- a/contracts/test/acl/acl.t.sol +++ b/contracts/test/acl/acl.t.sol @@ -166,7 +166,7 @@ contract ACLTest is Test { uint256[] memory handlesList = new uint256[](0); vm.prank(sender); vm.expectEmit(address(acl)); - emit ACL.AllowedForDecryption(handlesList); + emit ACL.AllowedForDecryption(address(sender), handlesList); acl.allowForDecryption(handlesList); } @@ -184,7 +184,7 @@ contract ACLTest is Test { vm.prank(sender); vm.expectEmit(address(acl)); - emit ACL.AllowedForDecryption(handlesList); + emit ACL.AllowedForDecryption(address(sender), handlesList); acl.allowForDecryption(handlesList); assertTrue(acl.isAllowedForDecryption(handle0)); diff --git a/contracts/test/coprocessorUtils.ts b/contracts/test/coprocessorUtils.ts index cdc35b6b..0476342d 100644 --- a/contracts/test/coprocessorUtils.ts +++ b/contracts/test/coprocessorUtils.ts @@ -815,205 +815,43 @@ function isCoprocAdd(longString: string): boolean { return normalizedLongString === coprocAdd; } -async function processLogs(trace, validSubcallsIndexes, blockStatus) { - for (const obj of trace.structLogs - .map((value, index) => ({ value, index })) - .filter((obj) => obj.value.op === 'CALL')) { - await insertHandle(obj, validSubcallsIndexes, blockStatus); - } -} - export const awaitCoprocessor = async (): Promise => { chainId = (await ethers.provider.getNetwork()).chainId; - if (process.env.HARDHAT_TFHEEXECUTOR_EVENTS !== '1') { - const pastTxHashes = await getAllPastTransactionHashes(); - for (const txHash of pastTxHashes) { - const trace = await ethers.provider.send('debug_traceTransaction', [txHash[0]]); - if (!trace.failed) { - const callTree = await buildCallTree(trace, txHash[1]); - const validSubcallsIndexes = getValidSubcallsIds(callTree)[1]; - await processLogs(trace, validSubcallsIndexes, { - timestamp: txHash[1].timestamp, - blockhash: txHash[1].blockhash, - }); - } - } - } else { - // with events we can go way faster since we don't need to trace all tx subcall - await processAllPastTFHEExecutorEvents(); - } + await processAllPastTFHEExecutorEvents(); }; -async function getAllPastTransactionHashes() { - const provider = ethers.provider; - const latestBlockNumber = await provider.getBlockNumber(); - let txHashes = []; - - if (hre.__SOLIDITY_COVERAGE_RUNNING !== true) { - // evm_snapshot is not supported in coverage mode - [lastBlockSnapshot, lastCounterRand] = await provider.send('get_lastBlockSnapshot'); - if (lastBlockSnapshot < firstBlockListening) { - firstBlockListening = lastBlockSnapshot + 1; - counterRand = Number(lastCounterRand); - } - } - - // Iterate through all blocks and collect transaction hashes - for (let i = firstBlockListening; i <= latestBlockNumber; i++) { - const block = await provider.getBlock(i, true); - block!.transactions.forEach((tx, index) => { - const rcpt = block?.prefetchedTransactions[index]; - txHashes.push([ - tx, - { to: rcpt.to, status: rcpt.status, blockhash: block?.parentHash, timestamp: block?.timestamp }, - ]); - }); - } - firstBlockListening = latestBlockNumber + 1; - if (hre.__SOLIDITY_COVERAGE_RUNNING !== true) { - // evm_snapshot is not supported in coverage mode - await provider.send('set_lastBlockSnapshot', [firstBlockListening]); - } - return txHashes; -} - -async function buildCallTree(trace, receipt) { - const structLogs = trace.structLogs; - - const callStack = []; - const callTree = { - id: 0, - type: !!receipt.to ? 'TOPCALL' : 'TOPCREATE', - revert: receipt.status === 1 ? false : true, - to: !!receipt.to ? receipt.to : null, - calls: [], - indexTrace: 0, - }; - let currentNode = callTree; - const lenStructLogs = structLogs.length; - let index = 1; - for (const [i, log] of structLogs.entries()) { - if (i < lenStructLogs - 1) { - if (structLogs[i].depth - structLogs[i + 1].depth === 1) { - if (!['RETURN', 'SELFDESTRUCT', 'STOP', 'REVERT', 'INVALID'].includes(structLogs[i].op)) { - currentNode.outofgasOrOther = true; - currentNode = callStack.pop(); - } - } - } - - switch (log.op) { - case 'CALL': - case 'DELEGATECALL': - case 'CALLCODE': - case 'STATICCALL': - case 'CREATE': - case 'CREATE2': - if (i < lenStructLogs - 1) { - if (structLogs[i + 1].depth - structLogs[i].depth === 1) { - const newNode = { - id: index, - type: log.op, - to: log.stack[log.stack.length - 2], - calls: [], - revert: true, - outofgasOrOther: false, - indexTrace: i, - }; - currentNode.calls.push(newNode); - callStack.push(currentNode); - currentNode = newNode; - index += 1; - } - } - break; - case 'RETURN': // some edge case probably not handled well : if memory expansion cost on RETURN exceeds the remaining gas in current subcall, but it's OK for a mocked mode - case 'SELFDESTRUCT': // some edge case probably not handled well : if there is not enough gas remaining on SELFDESTRUCT, but it's OK for a mocked mode - case 'STOP': - currentNode.revert = false; - currentNode = callStack.pop(); - break; - case 'REVERT': - case 'INVALID': - currentNode = callStack.pop(); - break; - } - - switch (log.op) { - case 'CREATE': - case 'CREATE2': - currentNode.to = null; - break; - } - } - return callTree; -} - -function logCallContextsTree(callContext, indent = 0) { - const indentation = ' '.repeat(indent); - console.log(`${indentation}id: ${callContext.id}, type: ${callContext.type}, revert: ${callContext.revert}`); - - if (callContext.calls.length > 0) { - console.log(`${indentation} Calls:`); - for (const call of callContext.calls) { - logCallContextsTree(call, indent + 4); - } - } -} - -function getValidSubcallsIds(tree) { - const result = []; - const resultIndexes = []; - - function traverse(node, ancestorReverted) { - if (ancestorReverted || node.revert) { - ancestorReverted = true; - } else { - result.push(node.id); - resultIndexes.push(node.indexTrace); - } - for (const child of node.calls) { - traverse(child, ancestorReverted); - } - } - - traverse(tree, false); - - return [result, resultIndexes]; -} - const abi = [ - 'event FheAdd(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', - 'event FheSub(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', - 'event FheMul(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', - 'event FheDiv(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', - 'event FheRem(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', - 'event FheBitAnd(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', - 'event FheBitOr(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', - 'event FheBitXor(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', - 'event FheShl(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', - 'event FheShr(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', - 'event FheRotl(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', - 'event FheRotr(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', - 'event FheEq(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', - 'event FheEqBytes(uint256 lhs, bytes rhs, bytes1 scalarByte, uint256 result)', - 'event FheNe(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', - 'event FheNeBytes(uint256 lhs, bytes rhs, bytes1 scalarByte, uint256 result)', - 'event FheGe(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', - 'event FheGt(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', - 'event FheLe(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', - 'event FheLt(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', - 'event FheMin(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', - 'event FheMax(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', - 'event FheNeg(uint256 ct, uint256 result)', - 'event FheNot(uint256 ct, uint256 result)', - 'event VerifyCiphertext(bytes32 inputHandle,address userAddress,bytes inputProof,bytes1 inputType,uint256 result)', - 'event Cast(uint256 ct, bytes1 toType, uint256 result)', - 'event TrivialEncrypt(uint256 pt, bytes1 toType, uint256 result)', - 'event TrivialEncryptBytes(bytes pt, bytes1 toType, uint256 result)', - 'event FheIfThenElse(uint256 control, uint256 ifTrue, uint256 ifFalse, uint256 result)', - 'event FheRand(bytes1 randType, bytes16 seed, uint256 result)', - 'event FheRandBounded(uint256 upperBound, bytes1 randType, bytes16 seed, uint256 result)', + 'event FheAdd(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', + 'event FheSub(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', + 'event FheMul(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', + 'event FheDiv(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', + 'event FheRem(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', + 'event FheBitAnd(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', + 'event FheBitOr(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', + 'event FheBitXor(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', + 'event FheShl(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', + 'event FheShr(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', + 'event FheRotl(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', + 'event FheRotr(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', + 'event FheEq(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', + 'event FheEqBytes(address indexed caller, uint256 lhs, bytes rhs, bytes1 scalarByte, uint256 result)', + 'event FheNe(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', + 'event FheNeBytes(address indexed caller, uint256 lhs, bytes rhs, bytes1 scalarByte, uint256 result)', + 'event FheGe(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', + 'event FheGt(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', + 'event FheLe(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', + 'event FheLt(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', + 'event FheMin(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', + 'event FheMax(address indexed caller, uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)', + 'event FheNeg(address indexed caller, uint256 ct, uint256 result)', + 'event FheNot(address indexed caller, uint256 ct, uint256 result)', + 'event VerifyCiphertext(address indexed caller, bytes32 inputHandle,address userAddress,bytes inputProof,bytes1 inputType,uint256 result)', + 'event Cast(address indexed caller, uint256 ct, bytes1 toType, uint256 result)', + 'event TrivialEncrypt(address indexed caller, uint256 pt, bytes1 toType, uint256 result)', + 'event TrivialEncryptBytes(address indexed caller, bytes pt, bytes1 toType, uint256 result)', + 'event FheIfThenElse(address indexed caller, uint256 control, uint256 ifTrue, uint256 ifFalse, uint256 result)', + 'event FheRand(address indexed caller, bytes1 randType, bytes16 seed, uint256 result)', + 'event FheRandBounded(address indexed caller, uint256 upperBound, bytes1 randType, bytes16 seed, uint256 result)', ]; async function processAllPastTFHEExecutorEvents() { @@ -1073,26 +911,26 @@ async function insertHandleFromEvent(event: FHEVMEvent) { switch (event.eventName) { case 'TrivialEncrypt': - clearText = event.args[0]; - handle = ethers.toBeHex(event.args[2], 32); + clearText = event.args[1]; + handle = ethers.toBeHex(event.args[3], 32); insertSQL(handle, clearText); break; case 'TrivialEncryptBytes': - clearText = event.args[0]; - handle = ethers.toBeHex(event.args[2], 32); + clearText = event.args[1]; + handle = ethers.toBeHex(event.args[3], 32); insertSQL(handle, clearText); break; case 'FheAdd': - handle = ethers.toBeHex(event.args[3], 32); + handle = ethers.toBeHex(event.args[4], 32); resultType = parseInt(handle.slice(-4, -2), 16); - clearLHS = await getClearText(event.args[0]); - if (event.args[2] === '0x01') { - clearText = BigInt(clearLHS) + event.args[1]; + clearLHS = await getClearText(event.args[1]); + if (event.args[3] === '0x01') { + clearText = BigInt(clearLHS) + event.args[2]; clearText = clearText % 2n ** NumBits[resultType]; } else { - clearRHS = await getClearText(event.args[1]); + clearRHS = await getClearText(event.args[2]); clearText = BigInt(clearLHS) + BigInt(clearRHS); clearText = clearText % 2n ** NumBits[resultType]; } @@ -1100,15 +938,15 @@ async function insertHandleFromEvent(event: FHEVMEvent) { break; case 'FheSub': - handle = ethers.toBeHex(event.args[3], 32); + handle = ethers.toBeHex(event.args[4], 32); resultType = parseInt(handle.slice(-4, -2), 16); - clearLHS = await getClearText(event.args[0]); - if (event.args[2] === '0x01') { - clearText = BigInt(clearLHS) - event.args[1]; + clearLHS = await getClearText(event.args[1]); + if (event.args[3] === '0x01') { + clearText = BigInt(clearLHS) - event.args[2]; if (clearText < 0n) clearText = clearText + 2n ** NumBits[resultType]; clearText = clearText % 2n ** NumBits[resultType]; } else { - clearRHS = await getClearText(event.args[1]); + clearRHS = await getClearText(event.args[2]); clearText = BigInt(clearLHS) - BigInt(clearRHS); if (clearText < 0n) clearText = clearText + 2n ** NumBits[resultType]; clearText = clearText % 2n ** NumBits[resultType]; @@ -1117,14 +955,14 @@ async function insertHandleFromEvent(event: FHEVMEvent) { break; case 'FheMul': - handle = ethers.toBeHex(event.args[3], 32); + handle = ethers.toBeHex(event.args[4], 32); resultType = parseInt(handle.slice(-4, -2), 16); - clearLHS = await getClearText(event.args[0]); - if (event.args[2] === '0x01') { - clearText = BigInt(clearLHS) * event.args[1]; + clearLHS = await getClearText(event.args[1]); + if (event.args[3] === '0x01') { + clearText = BigInt(clearLHS) * event.args[2]; clearText = clearText % 2n ** NumBits[resultType]; } else { - clearRHS = await getClearText(event.args[1]); + clearRHS = await getClearText(event.args[2]); clearText = BigInt(clearLHS) * BigInt(clearRHS); clearText = clearText % 2n ** NumBits[resultType]; } @@ -1132,11 +970,11 @@ async function insertHandleFromEvent(event: FHEVMEvent) { break; case 'FheDiv': - handle = ethers.toBeHex(event.args[3], 32); + handle = ethers.toBeHex(event.args[4], 32); resultType = parseInt(handle.slice(-4, -2), 16); - clearLHS = await getClearText(event.args[0]); - if (event.args[2] === '0x01') { - clearText = BigInt(clearLHS) / event.args[1]; + clearLHS = await getClearText(event.args[1]); + if (event.args[3] === '0x01') { + clearText = BigInt(clearLHS) / event.args[2]; } else { throw new Error('Non-scalar div not implemented yet'); } @@ -1144,11 +982,11 @@ async function insertHandleFromEvent(event: FHEVMEvent) { break; case 'FheRem': - handle = ethers.toBeHex(event.args[3], 32); + handle = ethers.toBeHex(event.args[4], 32); resultType = parseInt(handle.slice(-4, -2), 16); - clearLHS = await getClearText(event.args[0]); - if (event.args[2] === '0x01') { - clearText = BigInt(clearLHS) % event.args[1]; + clearLHS = await getClearText(event.args[1]); + if (event.args[3] === '0x01') { + clearText = BigInt(clearLHS) % event.args[2]; } else { throw new Error('Non-scalar rem not implemented yet'); } @@ -1156,14 +994,14 @@ async function insertHandleFromEvent(event: FHEVMEvent) { break; case 'FheBitAnd': - handle = ethers.toBeHex(event.args[3], 32); + handle = ethers.toBeHex(event.args[4], 32); resultType = parseInt(handle.slice(-4, -2), 16); - clearLHS = await getClearText(event.args[0]); - if (event.args[2] === '0x01') { - clearText = BigInt(clearLHS) & event.args[1]; + clearLHS = await getClearText(event.args[1]); + if (event.args[3] === '0x01') { + clearText = BigInt(clearLHS) & event.args[2]; clearText = clearText % 2n ** NumBits[resultType]; } else { - clearRHS = await getClearText(event.args[1]); + clearRHS = await getClearText(event.args[2]); clearText = BigInt(clearLHS) & BigInt(clearRHS); clearText = clearText % 2n ** NumBits[resultType]; } @@ -1171,14 +1009,14 @@ async function insertHandleFromEvent(event: FHEVMEvent) { break; case 'FheBitOr': - handle = ethers.toBeHex(event.args[3], 32); + handle = ethers.toBeHex(event.args[4], 32); resultType = parseInt(handle.slice(-4, -2), 16); - clearLHS = await getClearText(event.args[0]); - if (event.args[2] === '0x01') { - clearText = BigInt(clearLHS) | event.args[1]; + clearLHS = await getClearText(event.args[1]); + if (event.args[3] === '0x01') { + clearText = BigInt(clearLHS) | event.args[2]; clearText = clearText % 2n ** NumBits[resultType]; } else { - clearRHS = await getClearText(event.args[1]); + clearRHS = await getClearText(event.args[2]); clearText = BigInt(clearLHS) | BigInt(clearRHS); clearText = clearText % 2n ** NumBits[resultType]; } @@ -1186,14 +1024,14 @@ async function insertHandleFromEvent(event: FHEVMEvent) { break; case 'FheBitXor': - handle = ethers.toBeHex(event.args[3], 32); + handle = ethers.toBeHex(event.args[4], 32); resultType = parseInt(handle.slice(-4, -2), 16); - clearLHS = await getClearText(event.args[0]); - if (event.args[2] === '0x01') { - clearText = BigInt(clearLHS) ^ event.args[1]; + clearLHS = await getClearText(event.args[1]); + if (event.args[3] === '0x01') { + clearText = BigInt(clearLHS) ^ event.args[2]; clearText = clearText % 2n ** NumBits[resultType]; } else { - clearRHS = await getClearText(event.args[1]); + clearRHS = await getClearText(event.args[2]); clearText = BigInt(clearLHS) ^ BigInt(clearRHS); clearText = clearText % 2n ** NumBits[resultType]; } @@ -1201,14 +1039,14 @@ async function insertHandleFromEvent(event: FHEVMEvent) { break; case 'FheShl': - handle = ethers.toBeHex(event.args[3], 32); + handle = ethers.toBeHex(event.args[4], 32); resultType = parseInt(handle.slice(-4, -2), 16); - clearLHS = await getClearText(event.args[0]); - if (event.args[2] === '0x01') { - clearText = BigInt(clearLHS) << event.args[1] % NumBits[resultType]; + clearLHS = await getClearText(event.args[1]); + if (event.args[3] === '0x01') { + clearText = BigInt(clearLHS) << event.args[2] % NumBits[resultType]; clearText = clearText % 2n ** NumBits[resultType]; } else { - clearRHS = await getClearText(event.args[1]); + clearRHS = await getClearText(event.args[2]); clearText = BigInt(clearLHS) << BigInt(clearRHS) % NumBits[resultType]; clearText = clearText % 2n ** NumBits[resultType]; } @@ -1216,14 +1054,14 @@ async function insertHandleFromEvent(event: FHEVMEvent) { break; case 'FheShr': - handle = ethers.toBeHex(event.args[3], 32); + handle = ethers.toBeHex(event.args[4], 32); resultType = parseInt(handle.slice(-4, -2), 16); - clearLHS = await getClearText(event.args[0]); - if (event.args[2] === '0x01') { - clearText = BigInt(clearLHS) >> event.args[1] % NumBits[resultType]; + clearLHS = await getClearText(event.args[1]); + if (event.args[3] === '0x01') { + clearText = BigInt(clearLHS) >> event.args[2] % NumBits[resultType]; clearText = clearText % 2n ** NumBits[resultType]; } else { - clearRHS = await getClearText(event.args[1]); + clearRHS = await getClearText(event.args[2]); clearText = BigInt(clearLHS) >> BigInt(clearRHS) % NumBits[resultType]; clearText = clearText % 2n ** NumBits[resultType]; } @@ -1231,15 +1069,15 @@ async function insertHandleFromEvent(event: FHEVMEvent) { break; case 'FheRotl': - handle = ethers.toBeHex(event.args[3], 32); + handle = ethers.toBeHex(event.args[4], 32); resultType = parseInt(handle.slice(-4, -2), 16); - clearLHS = await getClearText(event.args[0]); - if (event.args[2] === '0x01') { - shift = event.args[1] % NumBits[resultType]; + clearLHS = await getClearText(event.args[1]); + if (event.args[3] === '0x01') { + shift = event.args[2] % NumBits[resultType]; clearText = (BigInt(clearLHS) << shift) | (BigInt(clearLHS) >> (NumBits[resultType] - shift)); clearText = clearText % 2n ** NumBits[resultType]; } else { - clearRHS = await getClearText(event.args[1]); + clearRHS = await getClearText(event.args[2]); shift = BigInt(clearRHS) % NumBits[resultType]; clearText = (BigInt(clearLHS) << shift) | (BigInt(clearLHS) >> (NumBits[resultType] - shift)); clearText = clearText % 2n ** NumBits[resultType]; @@ -1248,15 +1086,15 @@ async function insertHandleFromEvent(event: FHEVMEvent) { break; case 'FheRotr': - handle = ethers.toBeHex(event.args[3], 32); + handle = ethers.toBeHex(event.args[4], 32); resultType = parseInt(handle.slice(-4, -2), 16); - clearLHS = await getClearText(event.args[0]); - if (event.args[2] === '0x01') { - shift = event.args[1] % NumBits[resultType]; + clearLHS = await getClearText(event.args[1]); + if (event.args[3] === '0x01') { + shift = event.args[2] % NumBits[resultType]; clearText = (BigInt(clearLHS) >> shift) | (BigInt(clearLHS) << (NumBits[resultType] - shift)); clearText = clearText % 2n ** NumBits[resultType]; } else { - clearRHS = await getClearText(event.args[1]); + clearRHS = await getClearText(event.args[2]); shift = BigInt(clearRHS) % NumBits[resultType]; clearText = (BigInt(clearLHS) >> shift) | (BigInt(clearLHS) << (NumBits[resultType] - shift)); clearText = clearText % 2n ** NumBits[resultType]; @@ -1265,161 +1103,161 @@ async function insertHandleFromEvent(event: FHEVMEvent) { break; case 'FheEq': - handle = ethers.toBeHex(event.args[3], 32); + handle = ethers.toBeHex(event.args[4], 32); resultType = parseInt(handle.slice(-4, -2), 16); - clearLHS = await getClearText(event.args[0]); - if (event.args[2] === '0x01') { - clearText = BigInt(clearLHS) === event.args[1] ? 1n : 0n; + clearLHS = await getClearText(event.args[1]); + if (event.args[3] === '0x01') { + clearText = BigInt(clearLHS) === event.args[2] ? 1n : 0n; } else { - clearRHS = await getClearText(event.args[1]); + clearRHS = await getClearText(event.args[2]); clearText = BigInt(clearLHS) === BigInt(clearRHS) ? 1n : 0n; } insertSQL(handle, clearText); break; case 'FheEqBytes': - handle = ethers.toBeHex(event.args[3], 32); + handle = ethers.toBeHex(event.args[4], 32); resultType = parseInt(handle.slice(-4, -2), 16); - clearLHS = await getClearText(event.args[0]); - if (event.args[2] === '0x01') { - clearText = BigInt(clearLHS) === BigInt(event.args[1]) ? 1n : 0n; + clearLHS = await getClearText(event.args[1]); + if (event.args[3] === '0x01') { + clearText = BigInt(clearLHS) === BigInt(event.args[2]) ? 1n : 0n; } else { - clearRHS = await getClearText(event.args[1]); + clearRHS = await getClearText(event.args[2]); clearText = BigInt(clearLHS) === BigInt(clearRHS) ? 1n : 0n; } insertSQL(handle, clearText); break; case 'FheNe': - handle = ethers.toBeHex(event.args[3], 32); + handle = ethers.toBeHex(event.args[4], 32); resultType = parseInt(handle.slice(-4, -2), 16); - clearLHS = await getClearText(event.args[0]); - if (event.args[2] === '0x01') { - clearText = BigInt(clearLHS) !== event.args[1] ? 1n : 0n; + clearLHS = await getClearText(event.args[1]); + if (event.args[3] === '0x01') { + clearText = BigInt(clearLHS) !== event.args[2] ? 1n : 0n; } else { - clearRHS = await getClearText(event.args[1]); + clearRHS = await getClearText(event.args[2]); clearText = BigInt(clearLHS) !== BigInt(clearRHS) ? 1n : 0n; } insertSQL(handle, clearText); break; case 'FheNeBytes': - handle = ethers.toBeHex(event.args[3], 32); + handle = ethers.toBeHex(event.args[4], 32); resultType = parseInt(handle.slice(-4, -2), 16); - clearLHS = await getClearText(event.args[0]); - if (event.args[2] === '0x01') { - clearText = BigInt(clearLHS) !== BigInt(event.args[1]) ? 1n : 0n; + clearLHS = await getClearText(event.args[1]); + if (event.args[3] === '0x01') { + clearText = BigInt(clearLHS) !== BigInt(event.args[2]) ? 1n : 0n; } else { - clearRHS = await getClearText(event.args[1]); + clearRHS = await getClearText(event.args[2]); clearText = BigInt(clearLHS) !== BigInt(clearRHS) ? 1n : 0n; } insertSQL(handle, clearText); break; case 'FheGe': - handle = ethers.toBeHex(event.args[3], 32); + handle = ethers.toBeHex(event.args[4], 32); resultType = parseInt(handle.slice(-4, -2), 16); - clearLHS = await getClearText(event.args[0]); - if (event.args[2] === '0x01') { - clearText = BigInt(clearLHS) >= event.args[1] ? 1n : 0n; + clearLHS = await getClearText(event.args[1]); + if (event.args[3] === '0x01') { + clearText = BigInt(clearLHS) >= event.args[2] ? 1n : 0n; } else { - clearRHS = await getClearText(event.args[1]); + clearRHS = await getClearText(event.args[2]); clearText = BigInt(clearLHS) >= BigInt(clearRHS) ? 1n : 0n; } insertSQL(handle, clearText); break; case 'FheGt': - handle = ethers.toBeHex(event.args[3], 32); + handle = ethers.toBeHex(event.args[4], 32); resultType = parseInt(handle.slice(-4, -2), 16); - clearLHS = await getClearText(event.args[0]); - if (event.args[2] === '0x01') { - clearText = BigInt(clearLHS) > event.args[1] ? 1n : 0n; + clearLHS = await getClearText(event.args[1]); + if (event.args[3] === '0x01') { + clearText = BigInt(clearLHS) > event.args[2] ? 1n : 0n; } else { - clearRHS = await getClearText(event.args[1]); + clearRHS = await getClearText(event.args[2]); clearText = BigInt(clearLHS) > BigInt(clearRHS) ? 1n : 0n; } insertSQL(handle, clearText); break; case 'FheLe': - handle = ethers.toBeHex(event.args[3], 32); + handle = ethers.toBeHex(event.args[4], 32); resultType = parseInt(handle.slice(-4, -2), 16); - clearLHS = await getClearText(event.args[0]); - if (event.args[2] === '0x01') { - clearText = BigInt(clearLHS) <= event.args[1] ? 1n : 0n; + clearLHS = await getClearText(event.args[1]); + if (event.args[3] === '0x01') { + clearText = BigInt(clearLHS) <= event.args[2] ? 1n : 0n; } else { - clearRHS = await getClearText(event.args[1]); + clearRHS = await getClearText(event.args[2]); clearText = BigInt(clearLHS) <= BigInt(clearRHS) ? 1n : 0n; } insertSQL(handle, clearText); break; case 'FheLt': - handle = ethers.toBeHex(event.args[3], 32); + handle = ethers.toBeHex(event.args[4], 32); resultType = parseInt(handle.slice(-4, -2), 16); - clearLHS = await getClearText(event.args[0]); - if (event.args[2] === '0x01') { - clearText = BigInt(clearLHS) < event.args[1] ? 1n : 0n; + clearLHS = await getClearText(event.args[1]); + if (event.args[3] === '0x01') { + clearText = BigInt(clearLHS) < event.args[2] ? 1n : 0n; } else { - clearRHS = await getClearText(event.args[1]); + clearRHS = await getClearText(event.args[2]); clearText = BigInt(clearLHS) < BigInt(clearRHS) ? 1n : 0n; } insertSQL(handle, clearText); break; case 'FheMax': - handle = ethers.toBeHex(event.args[3], 32); + handle = ethers.toBeHex(event.args[4], 32); resultType = parseInt(handle.slice(-4, -2), 16); - clearLHS = await getClearText(event.args[0]); - if (event.args[2] === '0x01') { - clearText = BigInt(clearLHS) > event.args[1] ? clearLHS : event.args[1]; + clearLHS = await getClearText(event.args[1]); + if (event.args[3] === '0x01') { + clearText = BigInt(clearLHS) > event.args[2] ? clearLHS : event.args[2]; } else { - clearRHS = await getClearText(event.args[1]); + clearRHS = await getClearText(event.args[2]); clearText = BigInt(clearLHS) > BigInt(clearRHS) ? clearLHS : clearRHS; } insertSQL(handle, clearText); break; case 'FheMin': - handle = ethers.toBeHex(event.args[3], 32); + handle = ethers.toBeHex(event.args[4], 32); resultType = parseInt(handle.slice(-4, -2), 16); - clearLHS = await getClearText(event.args[0]); - if (event.args[2] === '0x01') { - clearText = BigInt(clearLHS) < event.args[1] ? clearLHS : event.args[1]; + clearLHS = await getClearText(event.args[1]); + if (event.args[3] === '0x01') { + clearText = BigInt(clearLHS) < event.args[2] ? clearLHS : event.args[2]; } else { - clearRHS = await getClearText(event.args[1]); + clearRHS = await getClearText(event.args[2]); clearText = BigInt(clearLHS) < BigInt(clearRHS) ? clearLHS : clearRHS; } insertSQL(handle, clearText); break; case 'Cast': - resultType = parseInt(event.args[1]); - handle = ethers.toBeHex(event.args[2], 32); - clearText = BigInt(await getClearText(event.args[0])) % 2n ** NumBits[resultType]; + resultType = parseInt(event.args[2]); + handle = ethers.toBeHex(event.args[3], 32); + clearText = BigInt(await getClearText(event.args[1])) % 2n ** NumBits[resultType]; insertSQL(handle, clearText); break; case 'FheNot': - handle = ethers.toBeHex(event.args[1], 32); + handle = ethers.toBeHex(event.args[2], 32); resultType = parseInt(handle.slice(-4, -2), 16); - clearText = BigInt(await getClearText(event.args[0])); + clearText = BigInt(await getClearText(event.args[1])); clearText = bitwiseNotUintBits(clearText, Number(NumBits[resultType])); insertSQL(handle, clearText); break; case 'FheNeg': - handle = ethers.toBeHex(event.args[1], 32); + handle = ethers.toBeHex(event.args[2], 32); resultType = parseInt(handle.slice(-4, -2), 16); - clearText = BigInt(await getClearText(event.args[0])); + clearText = BigInt(await getClearText(event.args[1])); clearText = bitwiseNotUintBits(clearText, Number(NumBits[resultType])); clearText = (clearText + 1n) % 2n ** NumBits[resultType]; insertSQL(handle, clearText); break; case 'VerifyCiphertext': - handle = event.args[0]; + handle = event.args[1]; try { await getClearText(BigInt(handle)); } catch { @@ -1428,12 +1266,12 @@ async function insertHandleFromEvent(event: FHEVMEvent) { break; case 'FheIfThenElse': - handle = ethers.toBeHex(event.args[3], 32); + handle = ethers.toBeHex(event.args[4], 32); resultType = parseInt(handle.slice(-4, -2), 16); - handle = ethers.toBeHex(event.args[3], 32); - const clearControl = BigInt(await getClearText(event.args[0])); - const clearIfTrue = BigInt(await getClearText(event.args[1])); - const clearIfFalse = BigInt(await getClearText(event.args[2])); + handle = ethers.toBeHex(event.args[4], 32); + const clearControl = BigInt(await getClearText(event.args[1])); + const clearIfTrue = BigInt(await getClearText(event.args[2])); + const clearIfFalse = BigInt(await getClearText(event.args[3])); if (clearControl === 1n) { clearText = clearIfTrue; } else { @@ -1443,17 +1281,17 @@ async function insertHandleFromEvent(event: FHEVMEvent) { break; case 'FheRand': - resultType = parseInt(event.args[0], 16); - handle = ethers.toBeHex(event.args[2], 32); + resultType = parseInt(event.args[1], 16); + handle = ethers.toBeHex(event.args[3], 32); clearText = getRandomBigInt(Number(NumBits[resultType])); insertSQL(handle, clearText, true); counterRand++; break; case 'FheRandBounded': - resultType = parseInt(event.args[1], 16); - handle = ethers.toBeHex(event.args[3], 32); - clearText = getRandomBigInt(Number(log2(BigInt(event.args[0])))); + resultType = parseInt(event.args[2], 16); + handle = ethers.toBeHex(event.args[4], 32); + clearText = getRandomBigInt(Number(log2(BigInt(event.args[1])))); insertSQL(handle, clearText, true); counterRand++; break; @@ -1461,9 +1299,6 @@ async function insertHandleFromEvent(event: FHEVMEvent) { } export function getFHEGasFromTxReceipt(receipt: ethers.TransactionReceipt): number { - if (process.env.HARDHAT_TFHEEXECUTOR_EVENTS !== '1') { - throw Error('FHEGas tracking is currently implemented only with TFHEExecutorWithEvents.sol variant'); - } if (receipt.status === 0) { throw new Error('Transaction reverted'); } @@ -1498,19 +1333,19 @@ export function getFHEGasFromTxReceipt(receipt: ethers.TransactionReceipt): numb let handle; switch (event.name) { case 'TrivialEncrypt': - type = parseInt(event.args[1], 16); + type = parseInt(event.args[2], 16); FHEGasConsumed += operatorsPrices['trivialEncrypt'].types[type]; break; case 'TrivialEncryptBytes': - type = parseInt(event.args[1], 16); + type = parseInt(event.args[2], 16); FHEGasConsumed += operatorsPrices['trivialEncrypt'].types[type]; break; case 'FheAdd': - handle = ethers.toBeHex(event.args[0], 32); + handle = ethers.toBeHex(event.args[1], 32); type = parseInt(handle.slice(-4, -2), 16); - if (event.args[2] === '0x01') { + if (event.args[3] === '0x01') { FHEGasConsumed += operatorsPrices['fheAdd'].scalar[type]; } else { FHEGasConsumed += operatorsPrices['fheAdd'].nonScalar[type]; @@ -1518,9 +1353,9 @@ export function getFHEGasFromTxReceipt(receipt: ethers.TransactionReceipt): numb break; case 'FheSub': - handle = ethers.toBeHex(event.args[0], 32); + handle = ethers.toBeHex(event.args[1], 32); type = parseInt(handle.slice(-4, -2), 16); - if (event.args[2] === '0x01') { + if (event.args[3] === '0x01') { FHEGasConsumed += operatorsPrices['fheSub'].scalar[type]; } else { FHEGasConsumed += operatorsPrices['fheSub'].nonScalar[type]; @@ -1528,9 +1363,9 @@ export function getFHEGasFromTxReceipt(receipt: ethers.TransactionReceipt): numb break; case 'FheMul': - handle = ethers.toBeHex(event.args[0], 32); + handle = ethers.toBeHex(event.args[1], 32); type = parseInt(handle.slice(-4, -2), 16); - if (event.args[2] === '0x01') { + if (event.args[3] === '0x01') { FHEGasConsumed += operatorsPrices['fheMul'].scalar[type]; } else { FHEGasConsumed += operatorsPrices['fheMul'].nonScalar[type]; @@ -1538,9 +1373,9 @@ export function getFHEGasFromTxReceipt(receipt: ethers.TransactionReceipt): numb break; case 'FheDiv': - handle = ethers.toBeHex(event.args[0], 32); + handle = ethers.toBeHex(event.args[1], 32); type = parseInt(handle.slice(-4, -2), 16); - if (event.args[2] === '0x01') { + if (event.args[3] === '0x01') { FHEGasConsumed += operatorsPrices['fheDiv'].scalar[type]; } else { throw new Error('Non-scalar div not implemented yet'); @@ -1548,9 +1383,9 @@ export function getFHEGasFromTxReceipt(receipt: ethers.TransactionReceipt): numb break; case 'FheRem': - handle = ethers.toBeHex(event.args[0], 32); + handle = ethers.toBeHex(event.args[1], 32); type = parseInt(handle.slice(-4, -2), 16); - if (event.args[2] === '0x01') { + if (event.args[3] === '0x01') { FHEGasConsumed += operatorsPrices['fheRem'].scalar[type]; } else { throw new Error('Non-scalar rem not implemented yet'); @@ -1558,9 +1393,9 @@ export function getFHEGasFromTxReceipt(receipt: ethers.TransactionReceipt): numb break; case 'FheBitAnd': - handle = ethers.toBeHex(event.args[0], 32); + handle = ethers.toBeHex(event.args[1], 32); type = parseInt(handle.slice(-4, -2), 16); - if (event.args[2] === '0x01') { + if (event.args[3] === '0x01') { FHEGasConsumed += operatorsPrices['fheBitAnd'].scalar[type]; } else { FHEGasConsumed += operatorsPrices['fheBitAnd'].nonScalar[type]; @@ -1568,9 +1403,9 @@ export function getFHEGasFromTxReceipt(receipt: ethers.TransactionReceipt): numb break; case 'FheBitOr': - handle = ethers.toBeHex(event.args[0], 32); + handle = ethers.toBeHex(event.args[1], 32); type = parseInt(handle.slice(-4, -2), 16); - if (event.args[2] === '0x01') { + if (event.args[3] === '0x01') { FHEGasConsumed += operatorsPrices['fheBitOr'].scalar[type]; } else { FHEGasConsumed += operatorsPrices['fheBitOr'].nonScalar[type]; @@ -1578,9 +1413,9 @@ export function getFHEGasFromTxReceipt(receipt: ethers.TransactionReceipt): numb break; case 'FheBitXor': - handle = ethers.toBeHex(event.args[0], 32); + handle = ethers.toBeHex(event.args[1], 32); type = parseInt(handle.slice(-4, -2), 16); - if (event.args[2] === '0x01') { + if (event.args[3] === '0x01') { FHEGasConsumed += operatorsPrices['fheBitXor'].scalar[type]; } else { FHEGasConsumed += operatorsPrices['fheBitXor'].nonScalar[type]; @@ -1588,9 +1423,9 @@ export function getFHEGasFromTxReceipt(receipt: ethers.TransactionReceipt): numb break; case 'FheShl': - handle = ethers.toBeHex(event.args[0], 32); + handle = ethers.toBeHex(event.args[1], 32); type = parseInt(handle.slice(-4, -2), 16); - if (event.args[2] === '0x01') { + if (event.args[3] === '0x01') { FHEGasConsumed += operatorsPrices['fheBitShl'].scalar[type]; } else { FHEGasConsumed += operatorsPrices['fheBitShl'].nonScalar[type]; @@ -1598,9 +1433,9 @@ export function getFHEGasFromTxReceipt(receipt: ethers.TransactionReceipt): numb break; case 'FheShr': - handle = ethers.toBeHex(event.args[0], 32); + handle = ethers.toBeHex(event.args[1], 32); type = parseInt(handle.slice(-4, -2), 16); - if (event.args[2] === '0x01') { + if (event.args[3] === '0x01') { FHEGasConsumed += operatorsPrices['fheBitShr'].scalar[type]; } else { FHEGasConsumed += operatorsPrices['fheBitShr'].nonScalar[type]; @@ -1608,9 +1443,9 @@ export function getFHEGasFromTxReceipt(receipt: ethers.TransactionReceipt): numb break; case 'FheRotl': - handle = ethers.toBeHex(event.args[0], 32); + handle = ethers.toBeHex(event.args[1], 32); type = parseInt(handle.slice(-4, -2), 16); - if (event.args[2] === '0x01') { + if (event.args[3] === '0x01') { FHEGasConsumed += operatorsPrices['fheRotl'].scalar[type]; } else { FHEGasConsumed += operatorsPrices['fheRotl'].nonScalar[type]; @@ -1618,9 +1453,9 @@ export function getFHEGasFromTxReceipt(receipt: ethers.TransactionReceipt): numb break; case 'FheRotr': - handle = ethers.toBeHex(event.args[0], 32); + handle = ethers.toBeHex(event.args[1], 32); type = parseInt(handle.slice(-4, -2), 16); - if (event.args[2] === '0x01') { + if (event.args[3] === '0x01') { FHEGasConsumed += operatorsPrices['fheRotr'].scalar[type]; } else { FHEGasConsumed += operatorsPrices['fheRotr'].nonScalar[type]; @@ -1628,9 +1463,9 @@ export function getFHEGasFromTxReceipt(receipt: ethers.TransactionReceipt): numb break; case 'FheEq': - handle = ethers.toBeHex(event.args[0], 32); + handle = ethers.toBeHex(event.args[1], 32); type = parseInt(handle.slice(-4, -2), 16); - if (event.args[2] === '0x01') { + if (event.args[3] === '0x01') { FHEGasConsumed += operatorsPrices['fheEq'].scalar[type]; } else { FHEGasConsumed += operatorsPrices['fheEq'].nonScalar[type]; @@ -1638,18 +1473,18 @@ export function getFHEGasFromTxReceipt(receipt: ethers.TransactionReceipt): numb break; case 'FheEqBytes': - handle = ethers.toBeHex(event.args[0], 32); + handle = ethers.toBeHex(event.args[1], 32); type = parseInt(handle.slice(-4, -2), 16); - if (event.args[2] === '0x01') { + if (event.args[3] === '0x01') { FHEGasConsumed += operatorsPrices['fheEq'].scalar[type]; } else { FHEGasConsumed += operatorsPrices['fheEq'].nonScalar[type]; } case 'FheNe': - handle = ethers.toBeHex(event.args[0], 32); + handle = ethers.toBeHex(event.args[1], 32); type = parseInt(handle.slice(-4, -2), 16); - if (event.args[2] === '0x01') { + if (event.args[3] === '0x01') { FHEGasConsumed += operatorsPrices['fheNe'].scalar[type]; } else { FHEGasConsumed += operatorsPrices['fheNe'].nonScalar[type]; @@ -1657,9 +1492,9 @@ export function getFHEGasFromTxReceipt(receipt: ethers.TransactionReceipt): numb break; case 'FheNeBytes': - handle = ethers.toBeHex(event.args[0], 32); + handle = ethers.toBeHex(event.args[1], 32); type = parseInt(handle.slice(-4, -2), 16); - if (event.args[2] === '0x01') { + if (event.args[3] === '0x01') { FHEGasConsumed += operatorsPrices['fheNe'].scalar[type]; } else { FHEGasConsumed += operatorsPrices['fheNe'].nonScalar[type]; @@ -1667,9 +1502,9 @@ export function getFHEGasFromTxReceipt(receipt: ethers.TransactionReceipt): numb break; case 'FheGe': - handle = ethers.toBeHex(event.args[0], 32); + handle = ethers.toBeHex(event.args[1], 32); type = parseInt(handle.slice(-4, -2), 16); - if (event.args[2] === '0x01') { + if (event.args[3] === '0x01') { FHEGasConsumed += operatorsPrices['fheGe'].scalar[type]; } else { FHEGasConsumed += operatorsPrices['fheGe'].nonScalar[type]; @@ -1677,9 +1512,9 @@ export function getFHEGasFromTxReceipt(receipt: ethers.TransactionReceipt): numb break; case 'FheGt': - handle = ethers.toBeHex(event.args[0], 32); + handle = ethers.toBeHex(event.args[1], 32); type = parseInt(handle.slice(-4, -2), 16); - if (event.args[2] === '0x01') { + if (event.args[3] === '0x01') { FHEGasConsumed += operatorsPrices['fheGt'].scalar[type]; } else { FHEGasConsumed += operatorsPrices['fheGt'].nonScalar[type]; @@ -1687,9 +1522,9 @@ export function getFHEGasFromTxReceipt(receipt: ethers.TransactionReceipt): numb break; case 'FheLe': - handle = ethers.toBeHex(event.args[0], 32); + handle = ethers.toBeHex(event.args[1], 32); type = parseInt(handle.slice(-4, -2), 16); - if (event.args[2] === '0x01') { + if (event.args[3] === '0x01') { FHEGasConsumed += operatorsPrices['fheLe'].scalar[type]; } else { FHEGasConsumed += operatorsPrices['fheLe'].nonScalar[type]; @@ -1697,9 +1532,9 @@ export function getFHEGasFromTxReceipt(receipt: ethers.TransactionReceipt): numb break; case 'FheLt': - handle = ethers.toBeHex(event.args[0], 32); + handle = ethers.toBeHex(event.args[1], 32); type = parseInt(handle.slice(-4, -2), 16); - if (event.args[2] === '0x01') { + if (event.args[3] === '0x01') { FHEGasConsumed += operatorsPrices['fheLt'].scalar[type]; } else { FHEGasConsumed += operatorsPrices['fheLt'].nonScalar[type]; @@ -1707,9 +1542,9 @@ export function getFHEGasFromTxReceipt(receipt: ethers.TransactionReceipt): numb break; case 'FheMax': - handle = ethers.toBeHex(event.args[0], 32); + handle = ethers.toBeHex(event.args[1], 32); type = parseInt(handle.slice(-4, -2), 16); - if (event.args[2] === '0x01') { + if (event.args[3] === '0x01') { FHEGasConsumed += operatorsPrices['fheMax'].scalar[type]; } else { FHEGasConsumed += operatorsPrices['fheMax'].nonScalar[type]; @@ -1717,9 +1552,9 @@ export function getFHEGasFromTxReceipt(receipt: ethers.TransactionReceipt): numb break; case 'FheMin': - handle = ethers.toBeHex(event.args[0], 32); + handle = ethers.toBeHex(event.args[1], 32); type = parseInt(handle.slice(-4, -2), 16); - if (event.args[2] === '0x01') { + if (event.args[3] === '0x01') { FHEGasConsumed += operatorsPrices['fheMin'].scalar[type]; } else { FHEGasConsumed += operatorsPrices['fheMin'].nonScalar[type]; @@ -1727,36 +1562,36 @@ export function getFHEGasFromTxReceipt(receipt: ethers.TransactionReceipt): numb break; case 'Cast': - handle = ethers.toBeHex(event.args[0], 32); + handle = ethers.toBeHex(event.args[1], 32); type = parseInt(handle.slice(-4, -2), 16); FHEGasConsumed += operatorsPrices['cast'].types[type]; break; case 'FheNot': - handle = ethers.toBeHex(event.args[0], 32); + handle = ethers.toBeHex(event.args[1], 32); type = parseInt(handle.slice(-4, -2), 16); FHEGasConsumed += operatorsPrices['fheNot'].types[type]; break; case 'FheNeg': - handle = ethers.toBeHex(event.args[0], 32); + handle = ethers.toBeHex(event.args[1], 32); type = parseInt(handle.slice(-4, -2), 16); FHEGasConsumed += operatorsPrices['fheNeg'].types[type]; break; case 'FheIfThenElse': - handle = ethers.toBeHex(event.args[3], 32); + handle = ethers.toBeHex(event.args[4], 32); type = parseInt(handle.slice(-4, -2), 16); FHEGasConsumed += operatorsPrices['ifThenElse'].types[type]; break; case 'FheRand': - type = parseInt(event.args[0], 16); + type = parseInt(event.args[1], 16); FHEGasConsumed += operatorsPrices['fheRand'].types[type]; break; case 'FheRandBounded': - type = parseInt(event.args[1], 16); + type = parseInt(event.args[2], 16); FHEGasConsumed += operatorsPrices['fheRandBounded'].types[type]; break; } diff --git a/contracts/test/encryptedERC20/EncryptedERC20.FHEGas.ts b/contracts/test/encryptedERC20/EncryptedERC20.FHEGas.ts index 56f27398..76ea4424 100644 --- a/contracts/test/encryptedERC20/EncryptedERC20.FHEGas.ts +++ b/contracts/test/encryptedERC20/EncryptedERC20.FHEGas.ts @@ -33,12 +33,10 @@ describe('EncryptedERC20:FHEGas', function () { ); const t2 = await tx.wait(); expect(t2?.status).to.eq(1); - if (process.env.HARDHAT_TFHEEXECUTOR_EVENTS === '1') { - // FHEGas tracking is currently implemented only with TFHEExecutorWithEvents.sol variant - const FHEGasConsumedTransfer = getFHEGasFromTxReceipt(t2); - console.log('FHEGas Consumed in transfer', FHEGasConsumedTransfer); - console.log('Native Gas Consumed in transfer', t2.gasUsed); - } + + const FHEGasConsumedTransfer = getFHEGasFromTxReceipt(t2); + console.log('FHEGas Consumed in transfer', FHEGasConsumedTransfer); + console.log('Native Gas Consumed in transfer', t2.gasUsed); }); it('should be able to transferFrom only if allowance is sufficient', async function () { @@ -66,11 +64,9 @@ describe('EncryptedERC20:FHEGas', function () { encryptedTransferAmount2.inputProof, ); const t3 = await tx3.wait(); - if (process.env.HARDHAT_TFHEEXECUTOR_EVENTS === '1') { - // FHEGas tracking is currently implemented only with TFHEExecutorWithEvents.sol variant - const FHEGasConsumedTransferFrom = getFHEGasFromTxReceipt(t3); - console.log('FHEGas Consumed in transferFrom', FHEGasConsumedTransferFrom); - console.log('Native Gas Consumed in transferFrom', t3.gasUsed); - } + + const FHEGasConsumedTransferFrom = getFHEGasFromTxReceipt(t3); + console.log('FHEGas Consumed in transferFrom', FHEGasConsumedTransferFrom); + console.log('Native Gas Consumed in transferFrom', t3.gasUsed); }); });