feat: symbolic computation of fhe operations handles

chore: fixed typo
This commit is contained in:
Joseph-André Turk
2024-08-23 18:04:18 +02:00
parent d658fa83b1
commit a13cb753e9
13 changed files with 307 additions and 545 deletions

View File

@@ -1,4 +1,6 @@
import dotenv from 'dotenv';
import { ethers } from 'ethers';
import * as fs from 'fs';
import { ProviderWrapper } from 'hardhat/plugins';
class CustomProvider extends ProviderWrapper {
@@ -24,9 +26,10 @@ class CustomProvider extends ProviderWrapper {
const blockNumberHex = await this._wrappedProvider.request({ method: 'eth_blockNumber' });
this.lastBlockSnapshot = parseInt(blockNumberHex);
this.lastBlockSnapshotForDecrypt = parseInt(blockNumberHex);
const parsedEnvCoprocessor = dotenv.parse(fs.readFileSync('lib/.env.exec'));
const coprocAdd = parsedEnvCoprocessor.TFHE_EXECUTOR_CONTRACT_ADDRESS;
const callData = {
to: '0x000000000000000000000000000000000000005d',
to: coprocAdd,
data: '0x1f20d85c',
};
this.lastCounterRand = await this._wrappedProvider.request({

View File

@@ -15,7 +15,6 @@ function generateAllFiles() {
writeFileSync('lib/Impl.sol', t.implSol(context, operators));
writeFileSync('lib/TFHE.sol', tfheSolSource);
writeFileSync('lib/FhevmLib.sol', t.fhevmLibSol(operators));
writeFileSync('lib/TFHEExecutor.sol', t.tfheExecutorSol(context, operators));
mkdirSync('examples/tests', { recursive: true });
ovShards.forEach((os) => {
writeFileSync(`examples/tests/TFHETestSuite${os.shardNumber}.sol`, testgen.generateSmartContract(os));

View File

@@ -51,7 +51,7 @@ function binaryOperatorImpl(op: Operator): string {
`
function ${op.name}(uint256 lhs, uint256 rhs${scalarArg}) internal returns (uint256 result) {
${scalarSection}
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).${fname}(lhs, rhs, scalarByte);
result = ITFHEExecutor(tfheExecutorAdd).${fname}(lhs, rhs, scalarByte);
}` + '\n'
);
}
@@ -68,7 +68,7 @@ export function implSol(ctx: CodegenContext, operators: Operator[]): string {
pragma solidity ^0.8.24;
import "./TFHE.sol";
import "./FHEVMCoprocessorAddress.sol";
import "./TFHEExecutorAddress.sol";
import "./ACLAddress.sol";
${coprocessorInterface}
@@ -113,29 +113,6 @@ ${fheLibInterface}
return res.join('');
}
export function tfheExecutorSol(ctx: CodegenContext, operators: Operator[]): string {
const res: string[] = [];
const tfheExecutor = generatelImplTFHEExecutor(operators);
res.push(`
// SPDX-License-Identifier: BSD-3-Clause-Clear
pragma solidity ^0.8.24;
import "./ACL.sol";
import "./ACLAddress.sol";
import "./FhevmLib.sol";
address constant EXT_TFHE_LIBRARY = address(${ctx.libFheAddress});
${tfheExecutor}
`);
return res.join('');
}
function operatorFheLibFunction(op: Operator): string {
if (op.fheLibName) {
return op.fheLibName;
@@ -149,75 +126,11 @@ function capitalizeFirstLetter(input: string): string {
return `${firstLetter}${theRest}`;
}
function generatelImplTFHEExecutor(operators: Operator[]): string {
const res: string[] = [];
res.push('contract TFHEExecutor {');
res.push('ACL private constant acl = ACL(address(aclAdd));');
operators.forEach((op) => {
let functionName = operatorFheLibFunction(op);
let functionArguments: string;
switch (op.arguments) {
case OperatorArguments.Binary:
let requireRhsIfNotScalar: string = '';
if (op.hasScalar && op.hasEncrypted) {
requireRhsIfNotScalar = `
if (scalarByte == 0x00) {
require(acl.isAllowed(rhs, msg.sender));
}
`;
} else if (op.hasEncrypted) {
requireRhsIfNotScalar = `require(acl.isAllowed(rhs, msg.sender));`;
}
functionArguments = `(uint256 lhs, uint256 rhs, bytes1 scalarByte)`;
const tailBinary = `external returns (uint256 result) {
require(acl.isAllowed(lhs, msg.sender));
${requireRhsIfNotScalar}
result = FhevmLib(address(EXT_TFHE_LIBRARY)).${functionName}(lhs, rhs, scalarByte);
acl.allowTransient(result, msg.sender); }`;
res.push(` function ${functionName}${functionArguments} ${tailBinary}`);
break;
case OperatorArguments.Unary:
functionArguments = '(uint256 ct)';
const tailUnary = `external returns (uint256 result) {
require(acl.isAllowed(ct, msg.sender));
result = FhevmLib(address(EXT_TFHE_LIBRARY)).${functionName}(ct);
acl.allowTransient(result, msg.sender); }`;
res.push(` function ${functionName}${functionArguments} ${tailUnary}`);
break;
}
});
res.push(tfheExecutorCustomFunctions());
res.push('}');
return res.join('\n');
}
function generateImplFhevmLibInterface(operators: Operator[]): string {
const res: string[] = [];
res.push('interface FhevmLib {');
operators.forEach((op) => {
let functionName = operatorFheLibFunction(op);
const tail = 'external pure returns (uint256 result);';
let functionArguments: string;
switch (op.arguments) {
case OperatorArguments.Binary:
functionArguments = '(uint256 lhs, uint256 rhs, bytes1 scalarByte)';
res.push(` function ${functionName}${functionArguments} ${tail}`);
break;
case OperatorArguments.Unary:
functionArguments = '(uint256 ct)';
res.push(` function ${functionName}${functionArguments} ${tail}`);
break;
}
});
res.push(fheLibCustomInterfaceFunctions());
res.push('}');
return res.join('\n');
@@ -226,7 +139,7 @@ function generateImplFhevmLibInterface(operators: Operator[]): string {
function generateImplCoprocessorInterface(operators: Operator[]): string {
const res: string[] = [];
res.push('interface IFHEVMCoprocessor {');
res.push('interface ITFHEExecutor {');
operators.forEach((op) => {
let functionName = operatorFheLibFunction(op);
const tail = 'external returns (uint256 result);';
@@ -252,14 +165,7 @@ function generateImplCoprocessorInterface(operators: Operator[]): string {
function fheLibCustomInterfaceFunctions(): string {
return `
function fhePubKey(bytes1 fromLib) external view returns (bytes memory result);
function verifyCiphertext(bytes32 inputHandle, address callerAddress, address contractAddress, bytes memory inputProof, bytes1 inputType) external pure returns (uint256 result);
function cast(uint256 ct, bytes1 toType) external pure returns (uint256 result);
function trivialEncrypt(uint256 ct, bytes1 toType) external pure returns (uint256 result);
function fheIfThenElse(uint256 control, uint256 ifTrue, uint256 ifFalse) external pure returns (uint256 result);
function fheArrayEq(uint256[] memory lhs, uint256[] memory rhs) external pure returns (uint256 result);
function fheRand(bytes1 randType, uint256 seed) external view returns (uint256 result);
function fheRandBounded(uint256 upperBound, bytes1 randType, uint256 seed) external view returns (uint256 result);
`;
}
@@ -286,40 +192,6 @@ function generateACLInterface(): string {
`;
}
function tfheExecutorCustomFunctions(): string {
return `
function verifyCiphertext(bytes32 inputHandle, address callerAddress, bytes memory inputProof, bytes1 inputType) external returns (uint256 result) {
result = FhevmLib(address(EXT_TFHE_LIBRARY)).verifyCiphertext(inputHandle, callerAddress, msg.sender, inputProof, inputType);
acl.allowTransient(result, msg.sender);
}
function cast(uint256 ct, bytes1 toType) external returns (uint256 result) {
require(acl.isAllowed(ct, msg.sender));
result = FhevmLib(address(EXT_TFHE_LIBRARY)).cast(ct, toType);
acl.allowTransient(result, msg.sender);
}
function trivialEncrypt(uint256 plaintext, bytes1 toType) external returns (uint256 result) {
result = FhevmLib(address(EXT_TFHE_LIBRARY)).trivialEncrypt(plaintext, toType);
acl.allowTransient(result, msg.sender);
}
function fheIfThenElse(uint256 control, uint256 ifTrue, uint256 ifFalse) external returns (uint256 result) {
require(acl.isAllowed(control, msg.sender));
require(acl.isAllowed(ifTrue, msg.sender));
require(acl.isAllowed(ifFalse, msg.sender));
result = FhevmLib(address(EXT_TFHE_LIBRARY)).fheIfThenElse(control, ifTrue, ifFalse);
acl.allowTransient(result, msg.sender);
}
function fheRand(bytes1 randType) external returns (uint256 result) {
result = FhevmLib(address(EXT_TFHE_LIBRARY)).fheRand(randType, 0);
acl.allowTransient(result, msg.sender);
}
function fheRandBounded(uint256 upperBound, bytes1 randType) external returns (uint256 result) {
result = FhevmLib(address(EXT_TFHE_LIBRARY)).fheRandBounded(upperBound, randType, 0);
acl.allowTransient(result, msg.sender);
}
function cleanTransientStorage() external {}
`;
}
export function tfheSol(
ctx: CodegenContext,
operators: Operator[],
@@ -842,7 +714,7 @@ function unaryOperatorImpl(op: Operator): string {
let fname = operatorFheLibFunction(op);
return `
function ${op.name}(uint256 ct) internal returns (uint256 result) {
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).${fname}(ct);
result = ITFHEExecutor(tfheExecutorAdd).${fname}(ct);
}
`;
}
@@ -1136,7 +1008,7 @@ function implCustomMethods(ctx: CodegenContext): string {
// 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) {
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).fheIfThenElse(control, ifTrue, ifFalse);
result = ITFHEExecutor(tfheExecutorAdd).fheIfThenElse(control, ifTrue, ifFalse);
}
function verify(
@@ -1144,7 +1016,7 @@ function implCustomMethods(ctx: CodegenContext): string {
bytes memory inputProof,
uint8 toType
) internal returns (uint256 result) {
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).verifyCiphertext(inputHandle, msg.sender, inputProof, bytes1(toType));
result = ITFHEExecutor(tfheExecutorAdd).verifyCiphertext(inputHandle, msg.sender, inputProof, bytes1(toType));
IACL(aclAdd).allowTransient(result, msg.sender);
}
@@ -1152,22 +1024,22 @@ function implCustomMethods(ctx: CodegenContext): string {
uint256 ciphertext,
uint8 toType
) internal returns (uint256 result) {
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).cast(ciphertext, bytes1(toType));
result = ITFHEExecutor(tfheExecutorAdd).cast(ciphertext, bytes1(toType));
}
function trivialEncrypt(
uint256 value,
uint8 toType
) internal returns (uint256 result) {
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).trivialEncrypt(value, bytes1(toType));
result = ITFHEExecutor(tfheExecutorAdd).trivialEncrypt(value, bytes1(toType));
}
function rand(uint8 randType) internal returns(uint256 result) {
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).fheRand(bytes1(randType));
result = ITFHEExecutor(tfheExecutorAdd).fheRand(bytes1(randType));
}
function randBounded(uint256 upperBound, uint8 randType) internal returns(uint256 result) {
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).fheRandBounded(upperBound, bytes1(randType));
result = ITFHEExecutor(tfheExecutorAdd).fheRandBounded(upperBound, bytes1(randType));
}
function allowTransient(uint256 handle, address account) internal {
@@ -1180,7 +1052,7 @@ function implCustomMethods(ctx: CodegenContext): string {
function cleanTransientStorage() internal {
IACL(aclAdd).cleanTransientStorage();
IFHEVMCoprocessor(fhevmCoprocessorAdd).cleanTransientStorage();
ITFHEExecutor(tfheExecutorAdd).cleanTransientStorage();
}
function isAllowed(uint256 handle, address account) internal view returns (bool) {

View File

@@ -3,6 +3,7 @@
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/utils/Strings.sol";
import "./TFHEExecutorAddress.sol";
contract ACL {
/// @notice Name of the contract
@@ -13,7 +14,7 @@ contract ACL {
uint256 private constant MINOR_VERSION = 1;
uint256 private constant PATCH_VERSION = 0;
address public immutable fhEVMcoprocessorAddress;
address public immutable tfheExecutorAddress = tfheExecutorAdd;
mapping(uint256 => bool) public allowedForDecryption;
@@ -28,15 +29,11 @@ contract ACL {
event RevokedDelegation(address indexed sender, address indexed delegatee, address indexed contractAddress);
event AllowedForDecryption(uint256[] handlesList);
constructor(address _coprocessorAddress) {
fhEVMcoprocessorAddress = _coprocessorAddress;
}
// allowTransient use of `handle` for address `account`.
// The caller must be allowed to use `handle` for allowTransient() to succeed. If not, allowTransient() reverts.
// @note: The Coprocessor contract can always `allowTransient`, contrarily to `allow`
function allowTransient(uint256 handle, address account) public {
if (msg.sender != fhEVMcoprocessorAddress) {
if (msg.sender != tfheExecutorAddress) {
require(isAllowed(handle, msg.sender), "sender isn't allowed");
}
bytes32 key = keccak256(abi.encodePacked(handle, account));
@@ -59,7 +56,7 @@ contract ACL {
}
function cleanTransientStorage() external {
// this function removes the transient allowances, could be useful for integration with Account Abstraction when bundling several UserOps calling the FHEVMCoprocessor
// this function removes the transient allowances, could be useful for integration with Account Abstraction when bundling several UserOps calling the TFHEExecutorCoprocessor
assembly {
let length := tload(0)
tstore(0, 0)

View File

@@ -1,5 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
pragma solidity ^0.8.24;
address constant fhevmCoprocessorAdd = 0x05fD9B5EFE0a996095f42Ed7e77c390810CF660c;

View File

@@ -3,30 +3,6 @@
pragma solidity ^0.8.24;
interface FhevmLib {
function fheAdd(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result);
function fheSub(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result);
function fheMul(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result);
function fheDiv(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result);
function fheRem(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result);
function fheBitAnd(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result);
function fheBitOr(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result);
function fheBitXor(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result);
function fheShl(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result);
function fheShr(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result);
function fheRotl(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result);
function fheRotr(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result);
function fheEq(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result);
function fheNe(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result);
function fheGe(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result);
function fheGt(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result);
function fheLe(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result);
function fheLt(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result);
function fheMin(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result);
function fheMax(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result);
function fheNeg(uint256 ct) external pure returns (uint256 result);
function fheNot(uint256 ct) external pure returns (uint256 result);
function fhePubKey(bytes1 fromLib) external view returns (bytes memory result);
function verifyCiphertext(
bytes32 inputHandle,
address callerAddress,
@@ -34,10 +10,4 @@ interface FhevmLib {
bytes memory inputProof,
bytes1 inputType
) external pure returns (uint256 result);
function cast(uint256 ct, bytes1 toType) external pure returns (uint256 result);
function trivialEncrypt(uint256 ct, bytes1 toType) external pure returns (uint256 result);
function fheIfThenElse(uint256 control, uint256 ifTrue, uint256 ifFalse) external pure returns (uint256 result);
function fheArrayEq(uint256[] memory lhs, uint256[] memory rhs) external pure returns (uint256 result);
function fheRand(bytes1 randType, uint256 seed) external returns (uint256 result);
function fheRandBounded(uint256 upperBound, bytes1 randType, uint256 seed) external returns (uint256 result);
}

View File

@@ -3,10 +3,10 @@
pragma solidity ^0.8.24;
import "./TFHE.sol";
import "./FHEVMCoprocessorAddress.sol";
import "./TFHEExecutorAddress.sol";
import "./ACLAddress.sol";
interface IFHEVMCoprocessor {
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);
@@ -58,7 +58,7 @@ library Impl {
} else {
scalarByte = 0x00;
}
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).fheAdd(lhs, rhs, scalarByte);
result = ITFHEExecutor(tfheExecutorAdd).fheAdd(lhs, rhs, scalarByte);
}
function sub(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
@@ -68,7 +68,7 @@ library Impl {
} else {
scalarByte = 0x00;
}
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).fheSub(lhs, rhs, scalarByte);
result = ITFHEExecutor(tfheExecutorAdd).fheSub(lhs, rhs, scalarByte);
}
function mul(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
@@ -78,32 +78,32 @@ library Impl {
} else {
scalarByte = 0x00;
}
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).fheMul(lhs, rhs, scalarByte);
result = ITFHEExecutor(tfheExecutorAdd).fheMul(lhs, rhs, scalarByte);
}
function div(uint256 lhs, uint256 rhs) internal returns (uint256 result) {
bytes1 scalarByte = 0x01;
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).fheDiv(lhs, rhs, scalarByte);
result = ITFHEExecutor(tfheExecutorAdd).fheDiv(lhs, rhs, scalarByte);
}
function rem(uint256 lhs, uint256 rhs) internal returns (uint256 result) {
bytes1 scalarByte = 0x01;
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).fheRem(lhs, rhs, scalarByte);
result = ITFHEExecutor(tfheExecutorAdd).fheRem(lhs, rhs, scalarByte);
}
function and(uint256 lhs, uint256 rhs) internal returns (uint256 result) {
bytes1 scalarByte = 0x00;
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).fheBitAnd(lhs, rhs, scalarByte);
result = ITFHEExecutor(tfheExecutorAdd).fheBitAnd(lhs, rhs, scalarByte);
}
function or(uint256 lhs, uint256 rhs) internal returns (uint256 result) {
bytes1 scalarByte = 0x00;
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).fheBitOr(lhs, rhs, scalarByte);
result = ITFHEExecutor(tfheExecutorAdd).fheBitOr(lhs, rhs, scalarByte);
}
function xor(uint256 lhs, uint256 rhs) internal returns (uint256 result) {
bytes1 scalarByte = 0x00;
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).fheBitXor(lhs, rhs, scalarByte);
result = ITFHEExecutor(tfheExecutorAdd).fheBitXor(lhs, rhs, scalarByte);
}
function shl(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
@@ -113,7 +113,7 @@ library Impl {
} else {
scalarByte = 0x00;
}
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).fheShl(lhs, rhs, scalarByte);
result = ITFHEExecutor(tfheExecutorAdd).fheShl(lhs, rhs, scalarByte);
}
function shr(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
@@ -123,7 +123,7 @@ library Impl {
} else {
scalarByte = 0x00;
}
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).fheShr(lhs, rhs, scalarByte);
result = ITFHEExecutor(tfheExecutorAdd).fheShr(lhs, rhs, scalarByte);
}
function rotl(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
@@ -133,7 +133,7 @@ library Impl {
} else {
scalarByte = 0x00;
}
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).fheRotl(lhs, rhs, scalarByte);
result = ITFHEExecutor(tfheExecutorAdd).fheRotl(lhs, rhs, scalarByte);
}
function rotr(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
@@ -143,7 +143,7 @@ library Impl {
} else {
scalarByte = 0x00;
}
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).fheRotr(lhs, rhs, scalarByte);
result = ITFHEExecutor(tfheExecutorAdd).fheRotr(lhs, rhs, scalarByte);
}
function eq(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
@@ -153,7 +153,7 @@ library Impl {
} else {
scalarByte = 0x00;
}
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).fheEq(lhs, rhs, scalarByte);
result = ITFHEExecutor(tfheExecutorAdd).fheEq(lhs, rhs, scalarByte);
}
function ne(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
@@ -163,7 +163,7 @@ library Impl {
} else {
scalarByte = 0x00;
}
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).fheNe(lhs, rhs, scalarByte);
result = ITFHEExecutor(tfheExecutorAdd).fheNe(lhs, rhs, scalarByte);
}
function ge(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
@@ -173,7 +173,7 @@ library Impl {
} else {
scalarByte = 0x00;
}
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).fheGe(lhs, rhs, scalarByte);
result = ITFHEExecutor(tfheExecutorAdd).fheGe(lhs, rhs, scalarByte);
}
function gt(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
@@ -183,7 +183,7 @@ library Impl {
} else {
scalarByte = 0x00;
}
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).fheGt(lhs, rhs, scalarByte);
result = ITFHEExecutor(tfheExecutorAdd).fheGt(lhs, rhs, scalarByte);
}
function le(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
@@ -193,7 +193,7 @@ library Impl {
} else {
scalarByte = 0x00;
}
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).fheLe(lhs, rhs, scalarByte);
result = ITFHEExecutor(tfheExecutorAdd).fheLe(lhs, rhs, scalarByte);
}
function lt(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
@@ -203,7 +203,7 @@ library Impl {
} else {
scalarByte = 0x00;
}
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).fheLt(lhs, rhs, scalarByte);
result = ITFHEExecutor(tfheExecutorAdd).fheLt(lhs, rhs, scalarByte);
}
function min(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
@@ -213,7 +213,7 @@ library Impl {
} else {
scalarByte = 0x00;
}
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).fheMin(lhs, rhs, scalarByte);
result = ITFHEExecutor(tfheExecutorAdd).fheMin(lhs, rhs, scalarByte);
}
function max(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) {
@@ -223,47 +223,42 @@ library Impl {
} else {
scalarByte = 0x00;
}
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).fheMax(lhs, rhs, scalarByte);
result = ITFHEExecutor(tfheExecutorAdd).fheMax(lhs, rhs, scalarByte);
}
function neg(uint256 ct) internal returns (uint256 result) {
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).fheNeg(ct);
result = ITFHEExecutor(tfheExecutorAdd).fheNeg(ct);
}
function not(uint256 ct) internal returns (uint256 result) {
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).fheNot(ct);
result = ITFHEExecutor(tfheExecutorAdd).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) {
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).fheIfThenElse(control, ifTrue, ifFalse);
result = ITFHEExecutor(tfheExecutorAdd).fheIfThenElse(control, ifTrue, ifFalse);
}
function verify(bytes32 inputHandle, bytes memory inputProof, uint8 toType) internal returns (uint256 result) {
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).verifyCiphertext(
inputHandle,
msg.sender,
inputProof,
bytes1(toType)
);
result = ITFHEExecutor(tfheExecutorAdd).verifyCiphertext(inputHandle, msg.sender, inputProof, bytes1(toType));
IACL(aclAdd).allowTransient(result, msg.sender);
}
function cast(uint256 ciphertext, uint8 toType) internal returns (uint256 result) {
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).cast(ciphertext, bytes1(toType));
result = ITFHEExecutor(tfheExecutorAdd).cast(ciphertext, bytes1(toType));
}
function trivialEncrypt(uint256 value, uint8 toType) internal returns (uint256 result) {
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).trivialEncrypt(value, bytes1(toType));
result = ITFHEExecutor(tfheExecutorAdd).trivialEncrypt(value, bytes1(toType));
}
function rand(uint8 randType) internal returns (uint256 result) {
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).fheRand(bytes1(randType));
result = ITFHEExecutor(tfheExecutorAdd).fheRand(bytes1(randType));
}
function randBounded(uint256 upperBound, uint8 randType) internal returns (uint256 result) {
result = IFHEVMCoprocessor(fhevmCoprocessorAdd).fheRandBounded(upperBound, bytes1(randType));
result = ITFHEExecutor(tfheExecutorAdd).fheRandBounded(upperBound, bytes1(randType));
}
function allowTransient(uint256 handle, address account) internal {
@@ -276,7 +271,7 @@ library Impl {
function cleanTransientStorage() internal {
IACL(aclAdd).cleanTransientStorage();
IFHEVMCoprocessor(fhevmCoprocessorAdd).cleanTransientStorage();
ITFHEExecutor(tfheExecutorAdd).cleanTransientStorage();
}
function isAllowed(uint256 handle, address account) internal view returns (bool) {

View File

@@ -3,43 +3,7 @@
pragma solidity ^0.8.24;
contract MockedPrecompile {
uint256 public counterRand = 0; // counter used for computing handles of randomness operators
uint256 constant HANDLE_VERSION = 0;
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
}
function isPowerOfTwo(uint256 x) internal pure returns (bool) {
return (x > 0) && ((x & (x - 1)) == 0);
}
uint8 public constant HANDLE_VERSION = 0;
/// @dev handle format for user inputs is: keccak256(keccak256(CiphertextFHEList)||index_handle)[0:29] || index_handle || handle_type || handle_version
/// @dev other handles format (fhe ops results) is: keccak256(keccak256(rawCiphertextFHEList)||index_handle)[0:30] || handle_type || handle_version
@@ -49,186 +13,6 @@ contract MockedPrecompile {
return typeCt;
}
function appendType(uint256 prehandle, uint8 handleType) internal pure returns (uint256 result) {
result = prehandle & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000;
result = result | (uint256(handleType) << 8); // append type
result = result | HANDLE_VERSION;
}
function requireType(uint256 handle, uint256 supportedTypes) internal pure {
uint8 typeCt = typeOf(handle);
require((1 << typeCt) & supportedTypes > 0, "Unsupported type");
}
function unaryOp(Operators op, uint256 ct) internal pure returns (uint256 result) {
result = uint256(keccak256(abi.encodePacked(op, ct)));
uint8 typeCt = typeOf(ct);
result = appendType(result, typeCt);
}
function binaryOp(
Operators op,
uint256 lhs,
uint256 rhs,
bytes1 scalarByte,
uint8 resultType
) internal pure returns (uint256 result) {
bytes1 scalar = scalarByte & 0x01;
if (scalar == 0x00) {
uint8 typeRhs = typeOf(rhs);
uint8 typeLhs = typeOf(lhs);
require(typeLhs == typeRhs, "Incompatible types for lhs and rhs");
}
result = uint256(keccak256(abi.encodePacked(op, lhs, rhs, scalar)));
result = appendType(result, resultType);
}
function ternaryOp(Operators op, uint256 lhs, uint256 middle, uint256 rhs) internal pure returns (uint256 result) {
uint8 typeLhs = typeOf(lhs);
uint8 typeMiddle = typeOf(middle);
uint8 typeRhs = typeOf(rhs);
require(typeLhs == 0, "Unsupported type for lhs"); // lhs must be ebool
require(typeMiddle == typeRhs, "Incompatible types for middle and rhs");
result = uint256(keccak256(abi.encodePacked(op, lhs, middle, rhs)));
result = appendType(result, typeMiddle);
}
function fheAdd(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result) {
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheAdd, lhs, rhs, scalarByte, typeOf(lhs));
}
function fheSub(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result) {
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheSub, lhs, rhs, scalarByte, typeOf(lhs));
}
function fheMul(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result) {
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheMul, lhs, rhs, scalarByte, typeOf(lhs));
}
function fheDiv(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result) {
require(scalarByte == 0x01, "Only fheDiv by a scalar is supported");
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheDiv, lhs, rhs, scalarByte, typeOf(lhs));
}
function fheRem(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result) {
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheRem, lhs, rhs, scalarByte, typeOf(lhs));
}
function fheBitAnd(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result) {
require(scalarByte == 0x00, "Only fheBitAnd by a ciphertext is supported");
uint256 supportedTypes = (1 << 0) + (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheBitAnd, lhs, rhs, scalarByte, typeOf(lhs));
}
function fheBitOr(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result) {
require(scalarByte == 0x00, "Only fheBitOr by a ciphertext is supported");
uint256 supportedTypes = (1 << 0) + (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheBitOr, lhs, rhs, scalarByte, typeOf(lhs));
}
function fheBitXor(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result) {
require(scalarByte == 0x00, "Only fheBitXor by a ciphertext is supported");
uint256 supportedTypes = (1 << 0) + (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheBitXor, lhs, rhs, scalarByte, typeOf(lhs));
}
function fheShl(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result) {
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheShl, lhs, rhs, scalarByte, typeOf(lhs));
}
function fheShr(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result) {
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheShr, lhs, rhs, scalarByte, typeOf(lhs));
}
function fheRotl(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result) {
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheRotl, lhs, rhs, scalarByte, typeOf(lhs));
}
function fheRotr(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result) {
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheRotr, lhs, rhs, scalarByte, typeOf(lhs));
}
function fheEq(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result) {
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 7) + (1 << 11);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheEq, lhs, rhs, scalarByte, 0);
}
function fheNe(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result) {
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 7) + (1 << 11);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheNe, lhs, rhs, scalarByte, 0);
}
function fheGe(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result) {
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheGe, lhs, rhs, scalarByte, 0);
}
function fheGt(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result) {
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheGt, lhs, rhs, scalarByte, 0);
}
function fheLe(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result) {
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheLe, lhs, rhs, scalarByte, 0);
}
function fheLt(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result) {
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheLt, lhs, rhs, scalarByte, 0);
}
function fheMin(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result) {
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheMin, lhs, rhs, scalarByte, typeOf(lhs));
}
function fheMax(uint256 lhs, uint256 rhs, bytes1 scalarByte) external pure returns (uint256 result) {
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheMax, lhs, rhs, scalarByte, typeOf(lhs));
}
function fheNeg(uint256 ct) external pure returns (uint256 result) {
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(ct, supportedTypes);
result = unaryOp(Operators.fheNeg, ct);
}
function fheNot(uint256 ct) external pure returns (uint256 result) {
uint256 supportedTypes = (1 << 0) + (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(ct, supportedTypes);
result = unaryOp(Operators.fheNot, ct);
}
function verifyCiphertext(
bytes32 inputHandle,
address /*callerAddress*/,
@@ -252,45 +36,4 @@ contract MockedPrecompile {
// check correct inputHandle was sent, corresponding to the inputProof: the 29 first bytes must be equal
require((inputHandle & mask) == (checkHandle & mask), "Wrong inputHandle");
}
function cast(uint256 ct, bytes1 toType) external pure returns (uint256 result) {
uint256 supportedTypesInput = (1 << 0) + (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(ct, supportedTypesInput);
uint256 supportedTypesOutput = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5); // @note: unsupported casting to ebool (use fheNe instead)
require((1 << uint8(toType)) & supportedTypesOutput > 0, "Unsupported output type");
uint8 typeCt = typeOf(ct);
require(bytes1(typeCt) != toType, "Cannot cast to same type");
result = uint256(keccak256(abi.encodePacked(Operators.cast, ct, toType)));
result = appendType(result, uint8(toType));
}
function trivialEncrypt(uint256 pt, bytes1 toType) external pure returns (uint256 result) {
uint256 supportedTypes = (1 << 0) + (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 7);
require((1 << uint8(toType)) & supportedTypes > 0, "Unsupported type");
result = uint256(keccak256(abi.encodePacked(Operators.trivialEncrypt, pt, toType)));
result = appendType(result, uint8(toType));
}
function fheIfThenElse(uint256 control, uint256 ifTrue, uint256 ifFalse) external pure returns (uint256 result) {
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 7);
requireType(ifTrue, supportedTypes);
result = ternaryOp(Operators.fheIfThenElse, control, ifTrue, ifFalse);
}
function fheRand(bytes1 randType, uint256 /*ok*/) external returns (uint256 result) {
uint256 supportedTypes = (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
require((1 << uint8(randType)) & supportedTypes > 0, "Unsupported erandom type");
result = uint256(keccak256(abi.encodePacked(Operators.fheRand, randType, counterRand)));
result = appendType(result, uint8(randType));
counterRand++;
}
function fheRandBounded(uint256 upperBound, bytes1 randType, uint256 /*ok*/) external returns (uint256 result) {
uint256 supportedTypes = (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
require((1 << uint8(randType)) & supportedTypes > 0, "Unsupported erandom type");
require(isPowerOfTwo(upperBound), "UpperBound must be a power of 2");
result = uint256(keccak256(abi.encodePacked(Operators.fheRandBounded, upperBound, randType, counterRand)));
result = appendType(result, uint8(randType));
counterRand++;
}
}

View File

@@ -5,199 +5,339 @@ pragma solidity ^0.8.24;
import "./ACL.sol";
import "./ACLAddress.sol";
import "./FhevmLib.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
address constant EXT_TFHE_LIBRARY = address(0x000000000000000000000000000000000000005d);
contract TFHEExecutor {
/// @notice Handle version
uint8 public constant HANDLE_VERSION = 0;
/// @notice Name of the contract
string private constant CONTRACT_NAME = "TFHEExecutor";
/// @notice Version of the contract
uint256 private constant MAJOR_VERSION = 0;
uint256 private constant MINOR_VERSION = 1;
uint256 private constant PATCH_VERSION = 0;
ACL private constant acl = ACL(address(aclAdd));
uint256 public counterRand = 0; // counter used for computing handles of randomness operators
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
}
function isPowerOfTwo(uint256 x) internal pure returns (bool) {
return (x > 0) && ((x & (x - 1)) == 0);
}
/// @dev handle format for user inputs is: keccak256(keccak256(CiphertextFHEList)||index_handle)[0:29] || index_handle || handle_type || handle_version
/// @dev other handles format (fhe ops results) is: keccak256(keccak256(rawCiphertextFHEList)||index_handle)[0:30] || handle_type || handle_version
/// @dev 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 returns (uint8) {
uint8 typeCt = uint8(handle >> 8);
return typeCt;
}
function appendType(uint256 prehandle, uint8 handleType) internal pure returns (uint256 result) {
result = prehandle & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000;
result = result | (uint256(handleType) << 8); // append type
result = result | HANDLE_VERSION;
}
function requireType(uint256 handle, uint256 supportedTypes) internal pure {
uint8 typeCt = typeOf(handle);
require((1 << typeCt) & supportedTypes > 0, "Unsupported type");
}
function unaryOp(Operators op, uint256 ct) internal pure returns (uint256 result) {
result = uint256(keccak256(abi.encodePacked(op, ct)));
uint8 typeCt = typeOf(ct);
result = appendType(result, typeCt);
}
function binaryOp(
Operators op,
uint256 lhs,
uint256 rhs,
bytes1 scalarByte,
uint8 resultType
) internal pure returns (uint256 result) {
bytes1 scalar = scalarByte & 0x01;
if (scalar == 0x00) {
uint8 typeRhs = typeOf(rhs);
uint8 typeLhs = typeOf(lhs);
require(typeLhs == typeRhs, "Incompatible types for lhs and rhs");
}
result = uint256(keccak256(abi.encodePacked(op, lhs, rhs, scalar)));
result = appendType(result, resultType);
}
function ternaryOp(Operators op, uint256 lhs, uint256 middle, uint256 rhs) internal returns (uint256 result) {
uint8 typeLhs = typeOf(lhs);
uint8 typeMiddle = typeOf(middle);
uint8 typeRhs = typeOf(rhs);
require(typeLhs == 0, "Unsupported type for lhs"); // lhs must be ebool
require(typeMiddle == typeRhs, "Incompatible types for middle and rhs");
result = uint256(keccak256(abi.encodePacked(op, lhs, middle, rhs)));
result = appendType(result, typeMiddle);
}
function fheAdd(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result) {
require(acl.isAllowed(lhs, msg.sender));
if (scalarByte == 0x00) {
require(acl.isAllowed(rhs, msg.sender));
}
result = FhevmLib(address(EXT_TFHE_LIBRARY)).fheAdd(lhs, rhs, scalarByte);
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheAdd, lhs, rhs, scalarByte, typeOf(lhs));
acl.allowTransient(result, msg.sender);
}
function fheSub(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result) {
require(acl.isAllowed(lhs, msg.sender));
if (scalarByte == 0x00) {
require(acl.isAllowed(rhs, msg.sender));
}
result = FhevmLib(address(EXT_TFHE_LIBRARY)).fheSub(lhs, rhs, scalarByte);
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheSub, lhs, rhs, scalarByte, typeOf(lhs));
acl.allowTransient(result, msg.sender);
}
function fheMul(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result) {
require(acl.isAllowed(lhs, msg.sender));
if (scalarByte == 0x00) {
require(acl.isAllowed(rhs, msg.sender));
}
result = FhevmLib(address(EXT_TFHE_LIBRARY)).fheMul(lhs, rhs, scalarByte);
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheMul, lhs, rhs, scalarByte, typeOf(lhs));
acl.allowTransient(result, msg.sender);
}
function fheDiv(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result) {
require(acl.isAllowed(lhs, msg.sender));
result = FhevmLib(address(EXT_TFHE_LIBRARY)).fheDiv(lhs, rhs, scalarByte);
require(scalarByte == 0x01, "Only fheDiv by a scalar is supported");
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheDiv, lhs, rhs, scalarByte, typeOf(lhs));
acl.allowTransient(result, msg.sender);
}
function fheRem(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result) {
require(acl.isAllowed(lhs, msg.sender));
result = FhevmLib(address(EXT_TFHE_LIBRARY)).fheRem(lhs, rhs, scalarByte);
require(scalarByte == 0x01, "Only fheRem by a scalar is supported");
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheRem, lhs, rhs, scalarByte, typeOf(lhs));
acl.allowTransient(result, msg.sender);
}
function fheBitAnd(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result) {
require(acl.isAllowed(lhs, msg.sender));
require(acl.isAllowed(rhs, msg.sender));
result = FhevmLib(address(EXT_TFHE_LIBRARY)).fheBitAnd(lhs, rhs, scalarByte);
require(scalarByte == 0x00, "Only fheBitAnd by a ciphertext is supported");
uint256 supportedTypes = (1 << 0) + (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheBitAnd, lhs, rhs, scalarByte, typeOf(lhs));
acl.allowTransient(result, msg.sender);
}
function fheBitOr(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result) {
require(acl.isAllowed(lhs, msg.sender));
require(acl.isAllowed(rhs, msg.sender));
result = FhevmLib(address(EXT_TFHE_LIBRARY)).fheBitOr(lhs, rhs, scalarByte);
require(scalarByte == 0x00, "Only fheBitOr by a ciphertext is supported");
uint256 supportedTypes = (1 << 0) + (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheBitOr, lhs, rhs, scalarByte, typeOf(lhs));
acl.allowTransient(result, msg.sender);
}
function fheBitXor(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result) {
require(acl.isAllowed(lhs, msg.sender));
require(acl.isAllowed(rhs, msg.sender));
result = FhevmLib(address(EXT_TFHE_LIBRARY)).fheBitXor(lhs, rhs, scalarByte);
require(scalarByte == 0x00, "Only fheBitXor by a ciphertext is supported");
uint256 supportedTypes = (1 << 0) + (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheBitXor, lhs, rhs, scalarByte, typeOf(lhs));
acl.allowTransient(result, msg.sender);
}
function fheShl(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result) {
require(acl.isAllowed(lhs, msg.sender));
if (scalarByte == 0x00) {
require(acl.isAllowed(rhs, msg.sender));
}
result = FhevmLib(address(EXT_TFHE_LIBRARY)).fheShl(lhs, rhs, scalarByte);
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheShl, lhs, rhs, scalarByte, typeOf(lhs));
acl.allowTransient(result, msg.sender);
}
function fheShr(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result) {
require(acl.isAllowed(lhs, msg.sender));
if (scalarByte == 0x00) {
require(acl.isAllowed(rhs, msg.sender));
}
result = FhevmLib(address(EXT_TFHE_LIBRARY)).fheShr(lhs, rhs, scalarByte);
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheShr, lhs, rhs, scalarByte, typeOf(lhs));
acl.allowTransient(result, msg.sender);
}
function fheRotl(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result) {
require(acl.isAllowed(lhs, msg.sender));
if (scalarByte == 0x00) {
require(acl.isAllowed(rhs, msg.sender));
}
result = FhevmLib(address(EXT_TFHE_LIBRARY)).fheRotl(lhs, rhs, scalarByte);
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheRotl, lhs, rhs, scalarByte, typeOf(lhs));
acl.allowTransient(result, msg.sender);
}
function fheRotr(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result) {
require(acl.isAllowed(lhs, msg.sender));
if (scalarByte == 0x00) {
require(acl.isAllowed(rhs, msg.sender));
}
result = FhevmLib(address(EXT_TFHE_LIBRARY)).fheRotr(lhs, rhs, scalarByte);
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheRotr, lhs, rhs, scalarByte, typeOf(lhs));
acl.allowTransient(result, msg.sender);
}
function fheEq(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result) {
require(acl.isAllowed(lhs, msg.sender));
if (scalarByte == 0x00) {
require(acl.isAllowed(rhs, msg.sender));
}
result = FhevmLib(address(EXT_TFHE_LIBRARY)).fheEq(lhs, rhs, scalarByte);
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 7) + (1 << 11);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheEq, lhs, rhs, scalarByte, 0);
acl.allowTransient(result, msg.sender);
}
function fheNe(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result) {
require(acl.isAllowed(lhs, msg.sender));
if (scalarByte == 0x00) {
require(acl.isAllowed(rhs, msg.sender));
}
result = FhevmLib(address(EXT_TFHE_LIBRARY)).fheNe(lhs, rhs, scalarByte);
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 7) + (1 << 11);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheNe, lhs, rhs, scalarByte, 0);
acl.allowTransient(result, msg.sender);
}
function fheGe(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result) {
require(acl.isAllowed(lhs, msg.sender));
if (scalarByte == 0x00) {
require(acl.isAllowed(rhs, msg.sender));
}
result = FhevmLib(address(EXT_TFHE_LIBRARY)).fheGe(lhs, rhs, scalarByte);
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheGe, lhs, rhs, scalarByte, 0);
acl.allowTransient(result, msg.sender);
}
function fheGt(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result) {
require(acl.isAllowed(lhs, msg.sender));
if (scalarByte == 0x00) {
require(acl.isAllowed(rhs, msg.sender));
}
result = FhevmLib(address(EXT_TFHE_LIBRARY)).fheGt(lhs, rhs, scalarByte);
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheGt, lhs, rhs, scalarByte, 0);
acl.allowTransient(result, msg.sender);
}
function fheLe(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result) {
require(acl.isAllowed(lhs, msg.sender));
if (scalarByte == 0x00) {
require(acl.isAllowed(rhs, msg.sender));
}
result = FhevmLib(address(EXT_TFHE_LIBRARY)).fheLe(lhs, rhs, scalarByte);
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheLe, lhs, rhs, scalarByte, 0);
acl.allowTransient(result, msg.sender);
}
function fheLt(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result) {
require(acl.isAllowed(lhs, msg.sender));
if (scalarByte == 0x00) {
require(acl.isAllowed(rhs, msg.sender));
}
result = FhevmLib(address(EXT_TFHE_LIBRARY)).fheLt(lhs, rhs, scalarByte);
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheLt, lhs, rhs, scalarByte, 0);
acl.allowTransient(result, msg.sender);
}
function fheMin(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result) {
require(acl.isAllowed(lhs, msg.sender));
if (scalarByte == 0x00) {
require(acl.isAllowed(rhs, msg.sender));
}
result = FhevmLib(address(EXT_TFHE_LIBRARY)).fheMin(lhs, rhs, scalarByte);
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheMin, lhs, rhs, scalarByte, typeOf(lhs));
acl.allowTransient(result, msg.sender);
}
function fheMax(uint256 lhs, uint256 rhs, bytes1 scalarByte) external returns (uint256 result) {
require(acl.isAllowed(lhs, msg.sender));
if (scalarByte == 0x00) {
require(acl.isAllowed(rhs, msg.sender));
}
result = FhevmLib(address(EXT_TFHE_LIBRARY)).fheMax(lhs, rhs, scalarByte);
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(lhs, supportedTypes);
result = binaryOp(Operators.fheMax, lhs, rhs, scalarByte, typeOf(lhs));
acl.allowTransient(result, msg.sender);
}
function fheNeg(uint256 ct) external returns (uint256 result) {
require(acl.isAllowed(ct, msg.sender));
result = FhevmLib(address(EXT_TFHE_LIBRARY)).fheNeg(ct);
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(ct, supportedTypes);
result = unaryOp(Operators.fheNeg, ct);
acl.allowTransient(result, msg.sender);
}
function fheNot(uint256 ct) external returns (uint256 result) {
require(acl.isAllowed(ct, msg.sender));
result = FhevmLib(address(EXT_TFHE_LIBRARY)).fheNot(ct);
uint256 supportedTypes = (1 << 0) + (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(ct, supportedTypes);
result = unaryOp(Operators.fheNot, ct);
acl.allowTransient(result, msg.sender);
}
@@ -216,29 +356,73 @@ contract TFHEExecutor {
);
acl.allowTransient(result, msg.sender);
}
function cast(uint256 ct, bytes1 toType) external returns (uint256 result) {
require(acl.isAllowed(ct, msg.sender));
result = FhevmLib(address(EXT_TFHE_LIBRARY)).cast(ct, toType);
uint256 supportedTypesInput = (1 << 0) + (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
requireType(ct, supportedTypesInput);
uint256 supportedTypesOutput = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5); // @note: unsupported casting to ebool (use fheNe instead)
require((1 << uint8(toType)) & supportedTypesOutput > 0, "Unsupported output type");
uint8 typeCt = typeOf(ct);
require(bytes1(typeCt) != toType, "Cannot cast to same type");
result = uint256(keccak256(abi.encodePacked(Operators.cast, ct, toType)));
result = appendType(result, uint8(toType));
acl.allowTransient(result, msg.sender);
}
function trivialEncrypt(uint256 plaintext, bytes1 toType) external returns (uint256 result) {
result = FhevmLib(address(EXT_TFHE_LIBRARY)).trivialEncrypt(plaintext, toType);
function trivialEncrypt(uint256 pt, bytes1 toType) external returns (uint256 result) {
uint256 supportedTypes = (1 << 0) + (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 7);
require((1 << uint8(toType)) & supportedTypes > 0, "Unsupported type");
result = uint256(keccak256(abi.encodePacked(Operators.trivialEncrypt, pt, toType)));
result = appendType(result, uint8(toType));
acl.allowTransient(result, msg.sender);
}
function fheIfThenElse(uint256 control, uint256 ifTrue, uint256 ifFalse) external returns (uint256 result) {
require(acl.isAllowed(control, msg.sender));
require(acl.isAllowed(ifTrue, msg.sender));
require(acl.isAllowed(ifFalse, msg.sender));
result = FhevmLib(address(EXT_TFHE_LIBRARY)).fheIfThenElse(control, ifTrue, ifFalse);
uint256 supportedTypes = (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5) + (1 << 7);
requireType(ifTrue, supportedTypes);
result = ternaryOp(Operators.fheIfThenElse, control, ifTrue, ifFalse);
acl.allowTransient(result, msg.sender);
}
function fheRand(bytes1 randType) external returns (uint256 result) {
result = FhevmLib(address(EXT_TFHE_LIBRARY)).fheRand(randType, 0);
uint256 supportedTypes = (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
require((1 << uint8(randType)) & supportedTypes > 0, "Unsupported erandom type");
result = uint256(keccak256(abi.encodePacked(Operators.fheRand, randType, counterRand)));
result = appendType(result, uint8(randType));
counterRand++;
acl.allowTransient(result, msg.sender);
}
function fheRandBounded(uint256 upperBound, bytes1 randType) external returns (uint256 result) {
result = FhevmLib(address(EXT_TFHE_LIBRARY)).fheRandBounded(upperBound, randType, 0);
uint256 supportedTypes = (1 << 2) + (1 << 3) + (1 << 4) + (1 << 5);
require((1 << uint8(randType)) & supportedTypes > 0, "Unsupported erandom type");
require(isPowerOfTwo(upperBound), "UpperBound must be a power of 2");
result = uint256(keccak256(abi.encodePacked(Operators.fheRandBounded, upperBound, randType, counterRand)));
result = appendType(result, uint8(randType));
counterRand++;
acl.allowTransient(result, msg.sender);
}
function cleanTransientStorage() external {}
/// @notice Getter for the name and version of the contract
/// @return string representing the name and the version of the contract
function getVersion() external pure returns (string memory) {
return
string(
abi.encodePacked(
CONTRACT_NAME,
" v",
Strings.toString(MAJOR_VERSION),
".",
Strings.toString(MINOR_VERSION),
".",
Strings.toString(PATCH_VERSION)
)
);
}
}

View File

@@ -0,0 +1,5 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
pragma solidity ^0.8.24;
address constant tfheExecutorAdd = 0x05fD9B5EFE0a996095f42Ed7e77c390810CF660c;

View File

@@ -1 +1 @@
{"aliveStatusCodes": [429, 200]}
{ "aliveStatusCodes": [429, 200] }

View File

@@ -63,8 +63,7 @@ task('task:deployIdentity').setAction(async function (taskArguments: TaskArgumen
task('task:deployACL').setAction(async function (taskArguments: TaskArguments, { ethers }) {
const deployer = (await ethers.getSigners())[9];
const factory = await ethers.getContractFactory('ACL');
const envConfigExec = dotenv.parse(fs.readFileSync('lib/.env.exec'));
const acl = await factory.connect(deployer).deploy(envConfigExec.TFHE_EXECUTOR_CONTRACT_ADDRESS);
const acl = await factory.connect(deployer).deploy();
await acl.waitForDeployment();
const address = await acl.getAddress();
const envConfigAcl = dotenv.parse(fs.readFileSync('lib/.env.acl'));

View File

@@ -51,13 +51,13 @@ task('task:computeTFHEExecutorAddress').setAction(async function (taskArguments:
pragma solidity ^0.8.24;
address constant fhevmCoprocessorAdd = ${execAddress};\n`;
address constant tfheExecutorAdd = ${execAddress};\n`;
try {
fs.writeFileSync('./lib/FHEVMCoprocessorAddress.sol', solidityTemplateCoprocessor, { encoding: 'utf8', flag: 'w' });
console.log('./lib/FHEVMCoprocessorAddress.sol file generated successfully!');
fs.writeFileSync('./lib/TFHEExecutorAddress.sol', solidityTemplateCoprocessor, { encoding: 'utf8', flag: 'w' });
console.log('./lib/TFHEExecutorAddress.sol file generated successfully!');
} catch (error) {
console.error('Failed to write ./lib/FHEVMCoprocessorAddress.sol', error);
console.error('Failed to write ./lib/TFHEExecutorAddress.sol', error);
}
});