Skip to content

Commit

Permalink
Merge pull request #483 from zama-ai/allowThis
Browse files Browse the repository at this point in the history
feat: added allowThis function and docs
  • Loading branch information
jatZama authored Aug 30, 2024
2 parents 5b70ce2 + aa11c4e commit 06ba86f
Show file tree
Hide file tree
Showing 20 changed files with 633 additions and 575 deletions.
22 changes: 21 additions & 1 deletion codegen/templates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,10 @@ function tfheAclMethods(supportedBits: number[]): string {
function allow(ebool value, address account) internal {
Impl.allow(ebool.unwrap(value), account);
}
function allowThis(ebool value) internal {
Impl.allow(ebool.unwrap(value), address(this));
}
`,
);

Expand All @@ -719,6 +723,10 @@ function tfheAclMethods(supportedBits: number[]): string {
function allow(euint${bits} value, address account) internal {
Impl.allow(euint${bits}.unwrap(value), account);
}
function allowThis(euint${bits} value) internal {
Impl.allow(euint${bits}.unwrap(value), address(this));
}
\n`,
),
);
Expand All @@ -729,9 +737,17 @@ function tfheAclMethods(supportedBits: number[]): string {
Impl.allow(eaddress.unwrap(value), account);
}
function allowThis(eaddress value) internal {
Impl.allow(eaddress.unwrap(value), address(this));
}
function allow(ebytes256 value, address account) internal {
Impl.allow(ebytes256.unwrap(value), account);
}
function allowThis(ebytes256 value) internal {
Impl.allow(ebytes256.unwrap(value), address(this));
}
`,
);

Expand Down Expand Up @@ -986,7 +1002,11 @@ function implCustomMethods(ctx: CodegenContext): string {
}

export function paymentSol(): string {
const res: string = `import "../lib/FHEPaymentAddress.sol";
const res: string = `// SPDX-License-Identifier: BSD-3-Clause-Clear
pragma solidity ^0.8.24;
import "../lib/FHEPaymentAddress.sol";
interface IFHEPayment {
function depositETH(address account) external payable;
Expand Down
2 changes: 1 addition & 1 deletion codegen/testgen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ function generateLibCallTest(os: OverloadShard, res: string[]) {
res.push(`${functionTypeToEncryptedType(o.returnType)} result = TFHE.${o.name}(${tfheArgs});`);
res.push('\n');
}
res.push('TFHE.allow(result, address(this));');
res.push('TFHE.allowThis(result);');
res.push(`${stateVar[functionTypeToEncryptedType(o.returnType) as keyof typeof stateVar]} = result;
}
`);
Expand Down
16 changes: 9 additions & 7 deletions docs/fundamentals/acl.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

## How it works?

fhEVM includes an Access Control List (ACL) system that allows you to define which addresses have the right to manipulate a ciphertext. This feature prevents any address from accessing the contents of any ciphertext.
fhEVM includes an Access Control List (ACL) system that allows you to define which addresses have the right to manipulate a ciphertext. This feature prevents any address from accessing the contents of unauthorized ciphertexts.

These ACLs can be adjusted in two ways:

- `TFHE.allow(ciphertext, address)` Permanently, on the blockchain. This allows a ciphertext to be used by a specific address at any time.
- `TFHE.allowTransient(ciphertext, address)` Temporarily. The ciphertext is then authorized only for the duration of the transaction.

Note that you can also use: `TFHE.allowThis(ciphertext)` which is just syntactic sugar instead of `TFHE.allow(ciphertext, address(this))`. This function is commonly used inside a dApp smart contract, in order to authorize the same contract to reuse a new `ciphertext` handle which has just been computed in a future transaction.

Permanent allowance will store the ACL in a dedicated contract, while a temporary allowance will store it in [transient storage](https://eips.ethereum.org/EIPS/eip-1153), allowing developers to save gas. Transient allowance is particularly useful when calling an external function using a ciphertext as a parameter.

To illustrate, here is a simple example where one function calls another:
Expand Down Expand Up @@ -49,26 +51,26 @@ contract SecretStore {
secretResult = computationResult;
// Make the temporary allowance for this ciphertext permanent to let the contract able to reuse it at a later stage or request a decryption of it
TFHE.allow(secretResult, address(this));
TFHE.allowThis(secretResult); // this is strictly equivalent to `TFHE.allow(secretResult, address(this));``
}
}
```

## Automatic (transient) allowance

To simplify matters, a number of functions automatically generate temporary access (using `TFHE.allowTransient`) for the contract that calls the function. This applies to:
To simplify matters, a number of functions automatically generate temporary access (using `TFHE.allowTransient` under the hood) for the contract that calls the function. This applies to:

- `TFHE.asEuintXX()`, `TFHE.asEaddress()`, `TFHE.asEbool()`
- `TFHE.randXX()`
- All results from computation (`TFHE.add()`, `TFHE.select()`, ...)
- All results from computations (`TFHE.add()`, `TFHE.select()`, ...)

```solidity
function randomize() {
// Store this random value. This value is temporarily allowed.
random = TFHE.randEuint64();
// Permanently store the temporary access for this ciphertext.
TFHE.allow(random, address(this));
TFHE.allowThis(random);
}
```

Expand All @@ -91,13 +93,13 @@ function transfer(address to, euint64 encryptedAmount) public {
euint64 newBalanceTo = TFHE.add(balances[to], TFHE.select(canTransfer, amount, TFHE.asEuint64(0)));
balances[to] = newBalanceTo;
// Allow this new balance for both the contract and the owner.
TFHE.allow(newBalanceTo, address(this));
TFHE.allowThis(newBalanceTo);
TFHE.allow(newBalanceTo, to);
euint64 newBalanceFrom = TFHE.sub(balances[from], TFHE.select(canTransfer, amount, TFHE.asEuint64(0)));
balances[from] = newBalanceFrom;
// Allow this new balance for both the contract and the owner.
TFHE.allow(newBalanceFrom, address(this));
TFHE.allowThis(newBalanceFrom);
TFHE.allow(newBalanceFrom, from);
}
```
6 changes: 3 additions & 3 deletions docs/fundamentals/types/conditions.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function bid(einput encryptedValue, bytes calldata inputProof) public onlyBefore
// Replace highest bid
highestBid = TFHE.select(isAbove, bid, highestBid);
TFHE.allow(highestBid, address(this));
TFHE.allowThis(highestBid);
}
```

Expand Down Expand Up @@ -52,11 +52,11 @@ function _transfer(address from, address to, euint32 amount) internal {
// Add to the balance of `to` and subract from the balance of `from`.
balances[to] = TFHE.add(balances[to], TFHE.select(canTransfer, amount, TFHE.asEuint32(0)));
TFHE.allow(balances[to], address(this));
TFHE.allowThis(balances[to]);
TFHE.allow(balances[to], to);
balances[from] = TFHE.sub(balances[from], TFHE.select(canTransfer, amount, TFHE.asEuint32(0)));
TFHE.allow(balances[from], address(this));
TFHE.allowThis(balances[from]);
TFHE.allow(balances[from], from);
}
```
4 changes: 2 additions & 2 deletions docs/guides/decrypt.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ contract TestAsyncDecrypt is GatewayCaller {
constructor() {
xBool = TFHE.asEbool(true);
TFHE.allow(xBool, address(this));
TFHE.allowThis(xBool);
}
function requestBool() public {
Expand Down Expand Up @@ -138,7 +138,7 @@ contract TestAsyncDecrypt is GatewayCaller {
constructor() {
xUint32 = TFHE.asEuint32(32);
TFHE.allow(xUint32, address(this));
TFHE.allowThis(xUint32);
}
function requestUint32(uint32 input1, uint32 input2) public {
Expand Down
10 changes: 5 additions & 5 deletions docs/guides/pitfalls.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ contract C {
constructor(uint32 _b) {
b = TFHE.asEuint32(_b);
TFHE.allow(b, address(this));
TFHE.allowThis(b);
}
}
```
Expand All @@ -29,7 +29,7 @@ contract C {
constructor(uint32 _b) {
b = TFHE.asEuint32(_b);
TFHE.allow(b, address(this));
TFHE.allowThis(b);
}
}
```
Expand Down Expand Up @@ -94,7 +94,7 @@ function setXwithEncryptedIndex(einput encryptedIndex, bytes calldata inputProof
ebool isEqual = TFHE.eq(index, i);
x = TFHE.select(isEqual, encArray[i], x);
}
TFHE.allow(x, address(this));
TFHE.allowThis(x);
}
```

Expand Down Expand Up @@ -131,7 +131,7 @@ function mint(einput encryptedAmount, bytes calldata inputProof) public {
euint32 mintedAmount = TFHE.asEuint32(encryptedAmount, inputProof);
totalSupply = TFHE.add(totalSupply, mintedAmount);
balances[msg.sender] = TFHE.add(balances[msg.sender], mintedAmount);
TFHE.allow(balances[msg.sender], address(this));
TFHE.allowThis(balances[msg.sender]);
TFHE.allow(balances[msg.sender], msg.sender);
}
```
Expand All @@ -146,7 +146,7 @@ function mint(einput encryptedAmount, bytes calldata inputProof) public {
totalSupply = TFHE.select(isOverflow, totalSupply, tempTotalSupply);
euint32 tempBalanceOf = TFHE.add(balances[msg.sender], mintedAmount);
balances[msg.sender] = TFHE.select(isOverflow, balances[msg.sender], tempBalanceOf);
TFHE.allow(balances[msg.sender], address(this));
TFHE.allowThis(balances[msg.sender]);
TFHE.allow(balances[msg.sender], msg.sender);
}
```
Expand Down
2 changes: 1 addition & 1 deletion docs/references/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ Allow an address to use a ciphertext, which includes computation, decryption, an
// Store a value in the contract.
r = TFHE.asEuint32(94);
// Set the contract as allowed for this ciphertext.
TFHE.allow(r, address(this));
TFHE.allowThis(r);
// Also set the caller as allowed for this ciphertext.
TFHE.allow(r, msg.sender);
```
Expand Down
14 changes: 7 additions & 7 deletions examples/BlindAuction.sol
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ contract BlindAuction is Ownable2Step, GatewayCaller {
tokenContract = _tokenContract;
endTime = block.timestamp + biddingTime;
objectClaimed = TFHE.asEbool(false);
TFHE.allow(objectClaimed, address(this));
TFHE.allowThis(objectClaimed);
tokenTransferred = false;
bidCounter = 0;
stoppable = isStoppable;
Expand Down Expand Up @@ -97,7 +97,7 @@ contract BlindAuction is Ownable2Step, GatewayCaller {
bids[msg.sender] = sentBalance;
}
euint64 currentBid = bids[msg.sender];
TFHE.allow(currentBid, address(this));
TFHE.allowThis(currentBid);
TFHE.allow(currentBid, msg.sender);

euint64 randTicket = TFHE.randEuint64();
Expand All @@ -117,8 +117,8 @@ contract BlindAuction is Ownable2Step, GatewayCaller {
highestBid = TFHE.select(isNewWinner, currentBid, highestBid);
winningTicket = TFHE.select(isNewWinner, userTicket, winningTicket);
}
TFHE.allow(highestBid, address(this));
TFHE.allow(winningTicket, address(this));
TFHE.allowThis(highestBid);
TFHE.allowThis(winningTicket);
TFHE.allow(userTicket, msg.sender);
}

Expand Down Expand Up @@ -158,10 +158,10 @@ contract BlindAuction is Ownable2Step, GatewayCaller {
function claim() public onlyAfterEnd {
ebool canClaim = TFHE.and(TFHE.eq(winningTicket, userTickets[msg.sender]), TFHE.not(objectClaimed));
objectClaimed = TFHE.or(canClaim, objectClaimed);
TFHE.allow(objectClaimed, address(this));
TFHE.allowThis(objectClaimed);
euint64 newBid = TFHE.select(canClaim, TFHE.asEuint64(0), bids[msg.sender]);
bids[msg.sender] = newBid;
TFHE.allow(bids[msg.sender], address(this));
TFHE.allowThis(bids[msg.sender]);
TFHE.allow(bids[msg.sender], msg.sender);
}

Expand All @@ -182,7 +182,7 @@ contract BlindAuction is Ownable2Step, GatewayCaller {
tokenContract.transfer(msg.sender, amount);
euint64 newBid = TFHE.select(canWithdraw, TFHE.asEuint64(0), bids[msg.sender]);
bids[msg.sender] = newBid;
TFHE.allow(newBid, address(this));
TFHE.allowThis(newBid);
TFHE.allow(newBid, msg.sender);
}

Expand Down
8 changes: 4 additions & 4 deletions examples/EncryptedERC20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ contract EncryptedERC20 is Ownable2Step {
// Sets the balance of the owner to the given encrypted balance.
function mint(uint64 mintedAmount) public virtual onlyOwner {
balances[owner()] = TFHE.add(balances[owner()], mintedAmount); // overflow impossible because of next line
TFHE.allow(balances[owner()], address(this));
TFHE.allowThis(balances[owner()]);
TFHE.allow(balances[owner()], owner());
_totalSupply = _totalSupply + mintedAmount;
emit Mint(owner(), mintedAmount);
Expand Down Expand Up @@ -115,7 +115,7 @@ contract EncryptedERC20 is Ownable2Step {

function _approve(address owner, address spender, euint64 amount) internal virtual {
allowances[owner][spender] = amount;
TFHE.allow(amount, address(this));
TFHE.allowThis(amount);
TFHE.allow(amount, owner);
TFHE.allow(amount, spender);
}
Expand All @@ -141,11 +141,11 @@ contract EncryptedERC20 is Ownable2Step {
euint64 transferValue = TFHE.select(isTransferable, amount, TFHE.asEuint64(0));
euint64 newBalanceTo = TFHE.add(balances[to], transferValue);
balances[to] = newBalanceTo;
TFHE.allow(newBalanceTo, address(this));
TFHE.allowThis(newBalanceTo);
TFHE.allow(newBalanceTo, to);
euint64 newBalanceFrom = TFHE.sub(balances[from], transferValue);
balances[from] = newBalanceFrom;
TFHE.allow(newBalanceFrom, address(this));
TFHE.allowThis(newBalanceFrom);
TFHE.allow(newBalanceFrom, from);
emit Transfer(from, to);
}
Expand Down
20 changes: 10 additions & 10 deletions examples/Rand.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,53 +18,53 @@ contract Rand {

function generate8() public {
value8 = TFHE.randEuint8();
TFHE.allow(value8, address(this));
TFHE.allowThis(value8);
}

function generate8UpperBound(uint8 upperBound) public {
value8 = TFHE.randEuint8(upperBound);
TFHE.allow(value8, address(this));
TFHE.allowThis(value8);
}

function generate16() public {
value16 = TFHE.randEuint16();
TFHE.allow(value16, address(this));
TFHE.allowThis(value16);
}

function generate16UpperBound(uint16 upperBound) public {
value16 = TFHE.randEuint16(upperBound);
TFHE.allow(value16, address(this));
TFHE.allowThis(value16);
}

function generate32() public {
value32 = TFHE.randEuint32();
TFHE.allow(value32, address(this));
TFHE.allowThis(value32);
}

function generate32UpperBound(uint32 upperBound) public {
value32 = TFHE.randEuint32(upperBound);
TFHE.allow(value32, address(this));
TFHE.allowThis(value32);
}

function generate64() public {
value64 = TFHE.randEuint64();
TFHE.allow(value64, address(this));
TFHE.allowThis(value64);
}

function generate64UpperBound(uint32 upperBound) public {
value64 = TFHE.randEuint64(upperBound);
TFHE.allow(value64, address(this));
TFHE.allowThis(value64);
}

function generate64Reverting() public {
try this.failingCall() {} catch {}
value64Bounded = TFHE.randEuint64(1024);
TFHE.allow(value64Bounded, address(this));
TFHE.allowThis(value64Bounded);
}

function failingCall() public {
value64 = TFHE.randEuint64();
TFHE.allow(value64, address(this));
TFHE.allowThis(value64);
revert();
}
}
Loading

0 comments on commit 06ba86f

Please sign in to comment.