From 8588a997c465acd672d51f3f1ba9a42836183bde Mon Sep 17 00:00:00 2001 From: Louis Tremblay Thibault Date: Tue, 5 Sep 2023 14:57:06 +0200 Subject: [PATCH 1/2] fix(lib): remove requires --- codegen/common.ts | 1 - codegen/templates.ts | 29 +++++------------------------ lib/Impl.sol | 14 -------------- lib/Precompiles.sol | 1 - lib/TFHE.sol | 10 ++-------- 5 files changed, 7 insertions(+), 48 deletions(-) diff --git a/codegen/common.ts b/codegen/common.ts index c1bedbd4..0c9233ff 100644 --- a/codegen/common.ts +++ b/codegen/common.ts @@ -37,7 +37,6 @@ export const ALL_PRECOMPILES: Precompile[] = [ { name: 'Verify', code: 66 }, { name: 'Reencrypt', code: 67 }, { name: 'FhePubKey', code: 68 }, - { name: 'Require', code: 69 }, { name: 'LessThanOrEqual', code: 70 }, { name: 'Subtract', code: 71 }, { name: 'Multiply', code: 72 }, diff --git a/codegen/templates.ts b/codegen/templates.ts index a2905384..10522f4a 100644 --- a/codegen/templates.ts +++ b/codegen/templates.ts @@ -446,12 +446,6 @@ function unaryOperatorImpl(op: Operator): string { function tfheCustomMethods(): string { return ` - // Require that the encrypted bool 'b' is true. - // Involves decrypting 'b'. - function req(ebool b) internal view { - Impl.req(ebool.unwrap(b)); - } - // Optimistically require that 'b' is true. // // This function does not evaluate 'b' at the time of the call. @@ -461,10 +455,11 @@ function tfheCustomMethods(): string { // gas cost, as if all optimistic requires were true. Yet, the transaction will be // reverted at the end if any of the optimisic requires were false. // - // Exceptions to above rule are encrypted requires via TFHE.req() and decryption via - // TFHE.decrypt(). If either of them are encountered and if optimistic requires have been - // used before in the txn, the optimisic requires will be immediately evaluated. Rationale is - // that we want to avoid decrypting a non-optimistic require or a value if the txn is about + // Exceptions to above rule are reencryptions and decryptions via + // TFHE.reencrypt() and TFHE.decrypt(), respectively. If either of them + // are encountered and if optimistic requires have been used before in the + // txn, the optimisic requires will be immediately evaluated. Rationale is + // that we want to avoid decrypting or reencrypting a value if the txn is about // to fail and be reverted anyway at the end. Checking immediately and reverting on the spot // would avoid unnecessary decryptions. // @@ -692,20 +687,6 @@ function implCustomMethods(): string { result = uint256(output[0]); } - function req(uint256 ciphertext) internal view { - bytes32[1] memory input; - input[0] = bytes32(ciphertext); - uint256 inputLen = 32; - - // Call the require precompile. - uint256 precompile = Precompiles.Require; - assembly { - if iszero(staticcall(gas(), precompile, input, inputLen, 0, 0)) { - revert(0, 0) - } - } - } - function decrypt(uint256 ciphertext) internal view returns(uint256 result) { bytes32[1] memory input; input[0] = bytes32(ciphertext); diff --git a/lib/Impl.sol b/lib/Impl.sol index d1fab720..a7e7446a 100644 --- a/lib/Impl.sol +++ b/lib/Impl.sol @@ -580,20 +580,6 @@ library Impl { result = uint256(output[0]); } - function req(uint256 ciphertext) internal view { - bytes32[1] memory input; - input[0] = bytes32(ciphertext); - uint256 inputLen = 32; - - // Call the require precompile. - uint256 precompile = Precompiles.Require; - assembly { - if iszero(staticcall(gas(), precompile, input, inputLen, 0, 0)) { - revert(0, 0) - } - } - } - function decrypt(uint256 ciphertext) internal view returns (uint256 result) { bytes32[1] memory input; input[0] = bytes32(ciphertext); diff --git a/lib/Precompiles.sol b/lib/Precompiles.sol index 9ecd0964..16de0edb 100644 --- a/lib/Precompiles.sol +++ b/lib/Precompiles.sol @@ -7,7 +7,6 @@ library Precompiles { uint256 public constant Verify = 66; uint256 public constant Reencrypt = 67; uint256 public constant FhePubKey = 68; - uint256 public constant Require = 69; uint256 public constant LessThanOrEqual = 70; uint256 public constant Subtract = 71; uint256 public constant Multiply = 72; diff --git a/lib/TFHE.sol b/lib/TFHE.sol index eb3dd0b4..bbbd0966 100644 --- a/lib/TFHE.sol +++ b/lib/TFHE.sol @@ -2483,12 +2483,6 @@ library TFHE { return euint32.wrap(Impl.not(euint32.unwrap(value))); } - // Require that the encrypted bool 'b' is true. - // Involves decrypting 'b'. - function req(ebool b) internal view { - Impl.req(ebool.unwrap(b)); - } - // Optimistically require that 'b' is true. // // This function does not evaluate 'b' at the time of the call. @@ -2498,10 +2492,10 @@ library TFHE { // gas cost, as if all optimistic requires were true. Yet, the transaction will be // reverted at the end if any of the optimisic requires were false. // - // Exceptions to above rule are encrypted requires via TFHE.req() and decryption via + // Exceptions to above rule are reencryptions and decryptions via // TFHE.decrypt(). If either of them are encountered and if optimistic requires have been // used before in the txn, the optimisic requires will be immediately evaluated. Rationale is - // that we want to avoid decrypting a non-optimistic require or a value if the txn is about + // that we want to avoid decrypting or reencrypting a value if the txn is about // to fail and be reverted anyway at the end. Checking immediately and reverting on the spot // would avoid unnecessary decryptions. // From d2b1491edeeb5a03b9411febcb1b2a555b4c66ec Mon Sep 17 00:00:00 2001 From: Louis Tremblay Thibault Date: Tue, 5 Sep 2023 15:10:13 +0200 Subject: [PATCH 2/2] fix(contracts): remove use of `TFHE.req` --- contracts/BlindAuction.sol | 4 ++-- contracts/EncryptedERC20.sol | 4 ++-- contracts/OptimisticRequire.sol | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/contracts/BlindAuction.sol b/contracts/BlindAuction.sol index aa9ac65a..e3445331 100644 --- a/contracts/BlindAuction.sol +++ b/contracts/BlindAuction.sol @@ -118,7 +118,7 @@ contract BlindAuction is EIP712WithModifier { // Claim the object. Succeeds only if the caller has the highest bid. function claim() public onlyAfterEnd { require(!objectClaimed); - TFHE.req(TFHE.le(highestBid, bids[msg.sender])); + require(TFHE.decrypt(TFHE.le(highestBid, bids[msg.sender]))); objectClaimed = true; bids[msg.sender] = TFHE.NIL32; @@ -137,7 +137,7 @@ contract BlindAuction is EIP712WithModifier { function withdraw() public onlyAfterEnd { euint32 bidValue = bids[msg.sender]; if (!objectClaimed) { - TFHE.req(TFHE.lt(bidValue, highestBid)); + require(TFHE.decrypt(TFHE.lt(bidValue, highestBid))); } tokenContract.transfer(msg.sender, bidValue); bids[msg.sender] = TFHE.NIL32; diff --git a/contracts/EncryptedERC20.sol b/contracts/EncryptedERC20.sol index 7d153108..8a7c8f36 100644 --- a/contracts/EncryptedERC20.sol +++ b/contracts/EncryptedERC20.sol @@ -104,14 +104,14 @@ contract EncryptedERC20 is EIP712WithModifier { function _updateAllowance(address owner, address spender, euint32 amount) internal { euint32 currentAllowance = _allowance(owner, spender); - TFHE.req(TFHE.le(amount, currentAllowance)); + require(TFHE.decrypt(TFHE.le(amount, currentAllowance))); _approve(owner, spender, TFHE.sub(currentAllowance, amount)); } // Transfers an encrypted amount. function _transfer(address from, address to, euint32 amount) internal { // Make sure the sender has enough tokens. - TFHE.req(TFHE.le(amount, balances[from])); + require(TFHE.decrypt(TFHE.le(amount, balances[from]))); // Add to the balance of `to` and subract from the balance of `from`. balances[to] = TFHE.add(balances[to], amount); diff --git a/contracts/OptimisticRequire.sol b/contracts/OptimisticRequire.sol index 5bf6c8fc..29b53844 100644 --- a/contracts/OptimisticRequire.sol +++ b/contracts/OptimisticRequire.sol @@ -60,10 +60,10 @@ contract OptimisticRequire { // Charge less than full gas, because the non-optimistic ciphertext require aborts early. function reqFalse() public { // True. - TFHE.req(TFHE.le(ct1, ct2)); + require(TFHE.decrypt(TFHE.le(ct1, ct2))); // False. - TFHE.req(TFHE.lt(ct1, ct2)); + require(TFHE.decrypt(TFHE.lt(ct1, ct2))); // Try to mutate state to pay for gas - we won't reach that point due to the false require. doWorkToPayGas();