mirror of
https://github.com/zama-ai/fhevm-solidity.git
synced 2026-01-14 06:58:06 -05:00
400 lines
16 KiB
Solidity
400 lines
16 KiB
Solidity
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
|
pragma solidity ^0.8.24;
|
|
|
|
import "./TFHE.sol";
|
|
|
|
/**
|
|
* @title FHEVMConfigStruct
|
|
* @notice This struct contains all addresses of core contrats which are needed in a typical dApp.
|
|
*/
|
|
struct FHEVMConfigStruct {
|
|
address ACLAddress;
|
|
address TFHEExecutorAddress;
|
|
address FHEPaymentAddress;
|
|
address KMSVerifierAddress;
|
|
}
|
|
|
|
/**
|
|
* @title ITFHEExecutor
|
|
* @notice This interface contains all functions to conduct FHE operations.
|
|
*/
|
|
interface ITFHEExecutor {
|
|
function fheAdd(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result);
|
|
function fheSub(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result);
|
|
function fheMul(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result);
|
|
function fheDiv(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result);
|
|
function fheRem(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result);
|
|
function fheBitAnd(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result);
|
|
function fheBitOr(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result);
|
|
function fheBitXor(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result);
|
|
function fheShl(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result);
|
|
function fheShr(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result);
|
|
function fheRotl(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result);
|
|
function fheRotr(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result);
|
|
function fheEq(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result);
|
|
function fheNe(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result);
|
|
function fheGe(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result);
|
|
function fheGt(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result);
|
|
function fheLe(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result);
|
|
function fheLt(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result);
|
|
function fheMin(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result);
|
|
function fheMax(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result);
|
|
function fheNeg(uint256 ct) external returns (uint256 result);
|
|
function fheNot(uint256 ct) external returns (uint256 result);
|
|
function verifyCiphertext(
|
|
bytes32 inputHandle,
|
|
address callerAddress,
|
|
bytes memory inputProof,
|
|
bytes1 inputType
|
|
) external returns (uint256 result);
|
|
function cast(uint256 ct, bytes1 toType) external returns (uint256 result);
|
|
function trivialEncrypt(uint256 ct, bytes1 toType) external returns (uint256 result);
|
|
function trivialEncrypt(bytes memory ct, bytes1 toType) external returns (uint256 result);
|
|
function fheEq(uint256 lhs, bytes memory rhs, bytes1 scalarByte) external returns (uint256 result);
|
|
function fheNe(uint256 lhs, bytes memory rhs, bytes1 scalarByte) external returns (uint256 result);
|
|
function fheIfThenElse(uint256 control, uint256 ifTrue, uint256 ifFalse) external returns (uint256 result);
|
|
function fheRand(bytes1 randType) external returns (uint256 result);
|
|
function fheRandBounded(uint256 upperBound, bytes1 randType) external returns (uint256 result);
|
|
}
|
|
|
|
/**
|
|
* @title IACL
|
|
* @notice This interface contains all functions that are used to conduct operations
|
|
* with the ACL contract.
|
|
*/
|
|
interface IACL {
|
|
function allowTransient(uint256 ciphertext, address account) external;
|
|
function allow(uint256 handle, address account) external;
|
|
function cleanTransientStorage() external;
|
|
function isAllowed(uint256 handle, address account) external view returns (bool);
|
|
function allowForDecryption(uint256[] memory handlesList) external;
|
|
}
|
|
|
|
/**
|
|
* @title Impl
|
|
* @notice This library is the core implementation for computing FHE operations (e.g. add, sub, xor).
|
|
*/
|
|
library Impl {
|
|
/// @dev keccak256(abi.encode(uint256(keccak256("fhevm.storage.FHEVMConfig")) - 1)) & ~bytes32(uint256(0xff))
|
|
bytes32 private constant FHEVMConfigLocation = 0xed8d60e34876f751cc8b014c560745351147d9de11b9347c854e881b128ea600;
|
|
|
|
function getFHEVMConfig() internal pure returns (FHEVMConfigStruct storage $) {
|
|
assembly {
|
|
$.slot := FHEVMConfigLocation
|
|
}
|
|
}
|
|
|
|
function setFHEVM(FHEVMConfigStruct memory fhevmConfig) internal {
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
$.ACLAddress = fhevmConfig.ACLAddress;
|
|
$.TFHEExecutorAddress = fhevmConfig.TFHEExecutorAddress;
|
|
$.FHEPaymentAddress = fhevmConfig.FHEPaymentAddress;
|
|
$.KMSVerifierAddress = fhevmConfig.KMSVerifierAddress;
|
|
}
|
|
|
|
function add(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
|
|
bytes1 scalarByte;
|
|
if (scalar) {
|
|
scalarByte = 0x01;
|
|
} else {
|
|
scalarByte = 0x00;
|
|
}
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).fheAdd(lhs, rhs, scalarByte);
|
|
}
|
|
|
|
function sub(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
|
|
bytes1 scalarByte;
|
|
if (scalar) {
|
|
scalarByte = 0x01;
|
|
} else {
|
|
scalarByte = 0x00;
|
|
}
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).fheSub(lhs, rhs, scalarByte);
|
|
}
|
|
|
|
function mul(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
|
|
bytes1 scalarByte;
|
|
if (scalar) {
|
|
scalarByte = 0x01;
|
|
} else {
|
|
scalarByte = 0x00;
|
|
}
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).fheMul(lhs, rhs, scalarByte);
|
|
}
|
|
|
|
function div(uint256 lhs, uint256 rhs) internal returns (uint256 result) {
|
|
bytes1 scalarByte = 0x01;
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).fheDiv(lhs, rhs, scalarByte);
|
|
}
|
|
|
|
function rem(uint256 lhs, uint256 rhs) internal returns (uint256 result) {
|
|
bytes1 scalarByte = 0x01;
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).fheRem(lhs, rhs, scalarByte);
|
|
}
|
|
|
|
function and(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
|
|
bytes1 scalarByte;
|
|
if (scalar) {
|
|
scalarByte = 0x01;
|
|
} else {
|
|
scalarByte = 0x00;
|
|
}
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).fheBitAnd(lhs, rhs, scalarByte);
|
|
}
|
|
|
|
function or(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
|
|
bytes1 scalarByte;
|
|
if (scalar) {
|
|
scalarByte = 0x01;
|
|
} else {
|
|
scalarByte = 0x00;
|
|
}
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).fheBitOr(lhs, rhs, scalarByte);
|
|
}
|
|
|
|
function xor(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
|
|
bytes1 scalarByte;
|
|
if (scalar) {
|
|
scalarByte = 0x01;
|
|
} else {
|
|
scalarByte = 0x00;
|
|
}
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).fheBitXor(lhs, rhs, scalarByte);
|
|
}
|
|
|
|
function shl(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
|
|
bytes1 scalarByte;
|
|
if (scalar) {
|
|
scalarByte = 0x01;
|
|
} else {
|
|
scalarByte = 0x00;
|
|
}
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).fheShl(lhs, rhs, scalarByte);
|
|
}
|
|
|
|
function shr(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
|
|
bytes1 scalarByte;
|
|
if (scalar) {
|
|
scalarByte = 0x01;
|
|
} else {
|
|
scalarByte = 0x00;
|
|
}
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).fheShr(lhs, rhs, scalarByte);
|
|
}
|
|
|
|
function rotl(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
|
|
bytes1 scalarByte;
|
|
if (scalar) {
|
|
scalarByte = 0x01;
|
|
} else {
|
|
scalarByte = 0x00;
|
|
}
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).fheRotl(lhs, rhs, scalarByte);
|
|
}
|
|
|
|
function rotr(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
|
|
bytes1 scalarByte;
|
|
if (scalar) {
|
|
scalarByte = 0x01;
|
|
} else {
|
|
scalarByte = 0x00;
|
|
}
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).fheRotr(lhs, rhs, scalarByte);
|
|
}
|
|
|
|
function eq(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
|
|
bytes1 scalarByte;
|
|
if (scalar) {
|
|
scalarByte = 0x01;
|
|
} else {
|
|
scalarByte = 0x00;
|
|
}
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).fheEq(lhs, rhs, scalarByte);
|
|
}
|
|
|
|
function ne(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
|
|
bytes1 scalarByte;
|
|
if (scalar) {
|
|
scalarByte = 0x01;
|
|
} else {
|
|
scalarByte = 0x00;
|
|
}
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).fheNe(lhs, rhs, scalarByte);
|
|
}
|
|
|
|
function ge(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
|
|
bytes1 scalarByte;
|
|
if (scalar) {
|
|
scalarByte = 0x01;
|
|
} else {
|
|
scalarByte = 0x00;
|
|
}
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).fheGe(lhs, rhs, scalarByte);
|
|
}
|
|
|
|
function gt(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
|
|
bytes1 scalarByte;
|
|
if (scalar) {
|
|
scalarByte = 0x01;
|
|
} else {
|
|
scalarByte = 0x00;
|
|
}
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).fheGt(lhs, rhs, scalarByte);
|
|
}
|
|
|
|
function le(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
|
|
bytes1 scalarByte;
|
|
if (scalar) {
|
|
scalarByte = 0x01;
|
|
} else {
|
|
scalarByte = 0x00;
|
|
}
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).fheLe(lhs, rhs, scalarByte);
|
|
}
|
|
|
|
function lt(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
|
|
bytes1 scalarByte;
|
|
if (scalar) {
|
|
scalarByte = 0x01;
|
|
} else {
|
|
scalarByte = 0x00;
|
|
}
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).fheLt(lhs, rhs, scalarByte);
|
|
}
|
|
|
|
function min(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
|
|
bytes1 scalarByte;
|
|
if (scalar) {
|
|
scalarByte = 0x01;
|
|
} else {
|
|
scalarByte = 0x00;
|
|
}
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).fheMin(lhs, rhs, scalarByte);
|
|
}
|
|
|
|
function max(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
|
|
bytes1 scalarByte;
|
|
if (scalar) {
|
|
scalarByte = 0x01;
|
|
} else {
|
|
scalarByte = 0x00;
|
|
}
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).fheMax(lhs, rhs, scalarByte);
|
|
}
|
|
|
|
function neg(uint256 ct) internal returns (uint256 result) {
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).fheNeg(ct);
|
|
}
|
|
|
|
function not(uint256 ct) internal returns (uint256 result) {
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).fheNot(ct);
|
|
}
|
|
|
|
// If 'control's value is 'true', the result has the same value as 'ifTrue'.
|
|
// If 'control's value is 'false', the result has the same value as 'ifFalse'.
|
|
function select(uint256 control, uint256 ifTrue, uint256 ifFalse) internal returns (uint256 result) {
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).fheIfThenElse(control, ifTrue, ifFalse);
|
|
}
|
|
|
|
function verify(bytes32 inputHandle, bytes memory inputProof, uint8 toType) internal returns (uint256 result) {
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).verifyCiphertext(
|
|
inputHandle,
|
|
msg.sender,
|
|
inputProof,
|
|
bytes1(toType)
|
|
);
|
|
IACL($.ACLAddress).allowTransient(result, msg.sender);
|
|
}
|
|
|
|
function cast(uint256 ciphertext, uint8 toType) internal returns (uint256 result) {
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).cast(ciphertext, bytes1(toType));
|
|
}
|
|
|
|
function trivialEncrypt(uint256 value, uint8 toType) internal returns (uint256 result) {
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).trivialEncrypt(value, bytes1(toType));
|
|
}
|
|
|
|
function trivialEncrypt(bytes memory value, uint8 toType) internal returns (uint256 result) {
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).trivialEncrypt(value, bytes1(toType));
|
|
}
|
|
|
|
function eq(uint256 lhs, bytes memory rhs, bool scalar) internal returns (uint256 result) {
|
|
bytes1 scalarByte;
|
|
if (scalar) {
|
|
scalarByte = 0x01;
|
|
} else {
|
|
scalarByte = 0x00;
|
|
}
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).fheEq(lhs, rhs, scalarByte);
|
|
}
|
|
|
|
function ne(uint256 lhs, bytes memory rhs, bool scalar) internal returns (uint256 result) {
|
|
bytes1 scalarByte;
|
|
if (scalar) {
|
|
scalarByte = 0x01;
|
|
} else {
|
|
scalarByte = 0x00;
|
|
}
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).fheNe(lhs, rhs, scalarByte);
|
|
}
|
|
|
|
function rand(uint8 randType) internal returns (uint256 result) {
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).fheRand(bytes1(randType));
|
|
}
|
|
|
|
function randBounded(uint256 upperBound, uint8 randType) internal returns (uint256 result) {
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
result = ITFHEExecutor($.TFHEExecutorAddress).fheRandBounded(upperBound, bytes1(randType));
|
|
}
|
|
|
|
function allowTransient(uint256 handle, address account) internal {
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
IACL($.ACLAddress).allowTransient(handle, account);
|
|
}
|
|
|
|
function allow(uint256 handle, address account) internal {
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
IACL($.ACLAddress).allow(handle, account);
|
|
}
|
|
|
|
function cleanTransientStorage() internal {
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
IACL($.ACLAddress).cleanTransientStorage();
|
|
}
|
|
|
|
function isAllowed(uint256 handle, address account) internal view returns (bool) {
|
|
FHEVMConfigStruct storage $ = getFHEVMConfig();
|
|
return IACL($.ACLAddress).isAllowed(handle, account);
|
|
}
|
|
}
|