Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 25 additions & 19 deletions tutorials/acl-usage-examples.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,14 @@ The contract that creates the value for the first time will automatically get ow

```solidity
// Contract A
function doAdd(InEuint32 input1, InEuint32 input2) {
euint32 handle1 = FHE.asEuint32(input1); // Contract A gets temporary ownership of handle1
euint32 handle2 = FHE.asEuint32(input2); // Contract A gets temporary ownership of handle2

euint32 result = FHE.add(handle1, handle2); // possible because Contract A has ownership of handle1 and handle2
function doAdd(externalEuint32 input1, externalEuint32 input2, bytes calldata inputProof) {
// Both inputs share one batch signature, so convert them together
externalEuint32[] memory inputs = new externalEuint32[](2);
inputs[0] = input1;
inputs[1] = input2;
euint32[] memory handles = FHE.asEuint32s(inputs, inputProof); // Contract A gets temporary ownership of both

euint32 result = FHE.add(handles[0], handles[1]); // possible because Contract A has ownership of both
}
```

Expand All @@ -44,11 +47,14 @@ contract A {
private euint32 result;
private euint32 handle1;

function doAdd(InEuint32 input1, InEuint32 input2) {
handle1 = FHE.asEuint32(input1); // Contract A gets temporary ownership of handle1
euint32 handle2 = FHE.asEuint32(input2); // Contract A gets temporary ownership of handle2
function doAdd(externalEuint32 input1, externalEuint32 input2, bytes calldata inputProof) {
externalEuint32[] memory inputs = new externalEuint32[](2);
inputs[0] = input1;
inputs[1] = input2;
euint32[] memory handles = FHE.asEuint32s(inputs, inputProof); // temporary ownership of both

result = FHE.add(handle1, handle2); // Contract A gets temporary ownership of result
handle1 = handles[0];
result = FHE.add(handles[0], handles[1]); // Contract A gets temporary ownership of result
FHE.allowThis(result); // result is allowed for future transactions
}

Expand All @@ -71,8 +77,8 @@ To decrypt a ciphertext offchain via the decryption network, the issuer must be
contract A {
private mapping(address => euint32) balances;

function transfer(InEuint32 _amount, address to) {
euint32 amount = FHE.asEuint32(_amount);
function transfer(externalEuint32 _amount, bytes calldata inputProof, address to) {
euint32 amount = FHE.asEuint32(_amount, inputProof);

balances[msg.sender] = FHE.sub(balances[msg.sender], amount);
balances[to] = FHE.add(balances[to], amount);
Expand All @@ -97,8 +103,8 @@ You can also allow other contracts to use your ciphertexts, either persistently

```solidity
contract A {
function doAdd(InEuint32 input1) {
euint32 handle1 = FHE.asEuint32(input1); // Contract A gets temporary ownership of handle1
function doAdd(externalEuint32 input1, bytes calldata inputProof) {
euint32 handle1 = FHE.asEuint32(input1, inputProof); // Contract A gets temporary ownership of handle1

FHE.allowTransient(handle1, addressB); // Contract B is allowed to use handle1 in this transaction alone
// or
Expand All @@ -120,8 +126,8 @@ Use `FHE.allowTransient()` when you only need to grant access for a single trans
When modifying encrypted values that users need to access:

```solidity
function updateBalance(address user, InEuint32 amount) public {
euint32 encryptedAmount = FHE.asEuint32(amount);
function updateBalance(address user, externalEuint32 amount, bytes calldata inputProof) public {
euint32 encryptedAmount = FHE.asEuint32(amount, inputProof);
balances[user] = FHE.add(balances[user], encryptedAmount);

// Allow contract to use in future transactions
Expand All @@ -137,8 +143,8 @@ function updateBalance(address user, InEuint32 amount) public {
A common pattern is to allow the message sender:

```solidity
function submitEncryptedData(InEuint32 data) public {
euint32 encryptedData = FHE.asEuint32(data);
function submitEncryptedData(externalEuint32 data, bytes calldata inputProof) public {
euint32 encryptedData = FHE.asEuint32(data, inputProof);
storedData[msg.sender] = encryptedData;

FHE.allowThis(storedData[msg.sender]);
Expand All @@ -151,8 +157,8 @@ function submitEncryptedData(InEuint32 data) public {
For values that should be accessible to everyone:

```solidity
function setPublicValue(InEuint32 value) public onlyOwner {
publicValue = FHE.asEuint32(value);
function setPublicValue(externalEuint32 value, bytes calldata inputProof) public onlyOwner {
publicValue = FHE.asEuint32(value, inputProof);
FHE.allowPublic(publicValue); // Everyone can now access this value
}
```
Expand Down
26 changes: 13 additions & 13 deletions tutorials/adding-fhe-to-existing-contract.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ The first thing that we need to do is import `FHE.sol` from the `cofhe-contracts
```solidity
pragma solidity ^0.8.25;

import {FHE, euint64, InEuint64} from "@fhenixprotocol/cofhe-contracts/FHE.sol";
import {FHE, euint64, externalEuint64} from "@fhenixprotocol/cofhe-contracts/FHE.sol";

contract VotingExample {
```
Expand Down Expand Up @@ -231,9 +231,9 @@ contract VotingExample {
}
```

### Step 4: Handle user votes with `InEuint8`
### Step 4: Handle user votes with `externalEuint8`

We now need to handle the user's vote casting. The first thing that we need to do is hide which option the user is voting for. We can do this by replacing the `vote` function parameter `uint256 _optionIndex` with `InEuint8 memory _optionIndex`. `InEuint8` is an encrypted input type. We then need to convert the `InEuint8` to an `euint8` for use in computation.
We now need to handle the user's vote casting. The first thing that we need to do is hide which option the user is voting for. We can do this by replacing the `vote` function parameter `uint256 _optionIndex` with two parameters: `externalEuint8 _optionIndex`, the encrypted input handle, and `bytes calldata inputProof`, the proof that authenticates it. `FHE.asEuint8(_optionIndex, inputProof)` then converts the pair into an `euint8` for use in computation.

<Note>
Encrypting inputs requires the use of the [**Client SDK**](/client-sdk/introduction/overview) (`@cofhe/sdk`).
Expand All @@ -242,17 +242,17 @@ Read more about [**encrypted inputs**](/client-sdk/guides/encrypting-inputs).
</Note>

```solidity
function vote(uint256 _proposalId, InEuint8 memory _optionIndex) external {
euint8 optionIndex = FHE.asEuint8(_optionIndex);
function vote(uint256 _proposalId, externalEuint8 _optionIndex, bytes calldata inputProof) external {
euint8 optionIndex = FHE.asEuint8(_optionIndex, inputProof);
```

### Step 5: Constant time computation

To preserve the confidentiality of the user's vote, we must make sure that we aren't leaking any information about the user's choice. If we only updated the voting option that the user has selected, then a user's vote could be deduced by simply watching which vote counter changes. Therefore, we must update _all_ the vote counters to hide the user's true vote:

```solidity
function vote(uint256 _proposalId, InEuint8 memory _optionIndex) external {
euint8 optionIndex = FHE.asEuint8(_optionIndex);
function vote(uint256 _proposalId, externalEuint8 _optionIndex, bytes calldata inputProof) external {
euint8 optionIndex = FHE.asEuint8(_optionIndex, inputProof);
Proposal storage proposal = proposals[_proposalId];

if (!proposal.exists) revert ProposalNotFound();
Expand Down Expand Up @@ -338,8 +338,8 @@ By default, access and computation on an encrypted variable is blocked, and tryi
- `FHE.allowPublic(ctHash)` - grants access to everyone, useful for things like an encrypted totalSupply variable, which everyone should have access to

```solidity
function vote(uint256 _proposalId, InEuint8 memory _optionIndex) external {
euint8 optionIndex = FHE.asEuint8(_optionIndex);
function vote(uint256 _proposalId, externalEuint8 _optionIndex, bytes calldata inputProof) external {
euint8 optionIndex = FHE.asEuint8(_optionIndex, inputProof);
Proposal storage proposal = proposals[_proposalId];

if (!proposal.exists) revert ProposalNotFound();
Expand Down Expand Up @@ -433,7 +433,7 @@ const signatures = [];
for (const option of proposal.options) {
const result = await client
.decryptForTx(option.votes)
.withoutPermit()
.withoutACP()
.execute();
decryptedVotes.push(result.decryptedValue);
signatures.push(result.signature);
Expand Down Expand Up @@ -528,7 +528,7 @@ The resulting contract provides the same functionality as the original, but with

pragma solidity ^0.8.25;

import {FHE, euint64, InEuint8} from "@fhenixprotocol/cofhe-contracts/FHE.sol";
import {FHE, euint64, externalEuint8} from "@fhenixprotocol/cofhe-contracts/FHE.sol";

contract FHEVotingExample {
struct Option {
Expand Down Expand Up @@ -607,8 +607,8 @@ contract FHEVotingExample {
return proposalId;
}

function vote(uint256 _proposalId, InEuint8 memory _optionIndex) external {
euint8 optionIndex = FHE.asEuint8(_optionIndex);
function vote(uint256 _proposalId, externalEuint8 _optionIndex, bytes calldata inputProof) external {
euint8 optionIndex = FHE.asEuint8(_optionIndex, inputProof);
Proposal storage proposal = proposals[_proposalId];

if (!proposal.exists) revert ProposalNotFound();
Expand Down
6 changes: 3 additions & 3 deletions tutorials/migrating-from-fhe-decrypt.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ The client requests decryption from the Threshold Network, which returns the pla
```typescript
const result = await client
.decryptForTx(ctHash)
.withoutPermit() // use .withPermit() if FHE.allow was used instead of allowPublic
.withoutACP() // use .withACP() if FHE.allow was used instead of allowPublic
.execute();

// result.decryptedValue — the plaintext (bigint)
Expand Down Expand Up @@ -135,7 +135,7 @@ await counter.allow_counter_publicly();
const ctHash = await counter.counter();
const result = await client
.decryptForTx(ctHash)
.withoutPermit()
.withoutACP()
.execute();

// 3. Publish on-chain with proof
Expand Down Expand Up @@ -231,7 +231,7 @@ const ctHash = /* ... from UnshieldedERC20 event ... */;
// 3. Decrypt off-chain
const result = await client
.decryptForTx(ctHash)
.withoutPermit()
.withoutACP()
.execute();

// 4. Claim with proof
Expand Down
18 changes: 9 additions & 9 deletions tutorials/your-first-fhe-contract.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Let's take a look at a simple contract that uses FHE to encrypt a counter, and b
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

import {FHE, euint64, InEuint64} from "@fhenixprotocol/cofhe-contracts/FHE.sol";
import {FHE, euint64, externalEuint64} from "@fhenixprotocol/cofhe-contracts/FHE.sol";

contract SimpleCounter {
address owner;
Expand Down Expand Up @@ -46,8 +46,8 @@ contract SimpleCounter {
FHE.allowThis(counter);
}

function reset_counter(InEuint64 calldata value) external onlyOwner {
counter = FHE.asEuint64(value);
function reset_counter(externalEuint64 value, bytes calldata inputProof) external onlyOwner {
counter = FHE.asEuint64(value, inputProof);
FHE.allowThis(counter);
}

Expand Down Expand Up @@ -79,10 +79,10 @@ contract SimpleCounter {

To start using FHE, we need to import the FHE library.

In this example, we're importing the types `euint64` and `InEuint64` from the [FHE library](/fhe-library/reference/fhe-sol/overview).
In this example, we're importing the types `euint64` and `externalEuint64` from the [FHE library](/fhe-library/reference/fhe-sol/overview).

```solidity
import {FHE, euint64, InEuint64} from "@fhenixprotocol/cofhe-contracts/FHE.sol";
import {FHE, euint64, externalEuint64} from "@fhenixprotocol/cofhe-contracts/FHE.sol";
```

We want to keep the counter encrypted at all times, so we'll use the `euint64` type.
Expand Down Expand Up @@ -151,9 +151,9 @@ FHE.allowThis(counter);

### Reset Function

In the `reset_counter` function, we receive an `InEuint64` value, which is a type that represents an encrypted value that can be used to reset the counter.
In the `reset_counter` function, we receive an `externalEuint64` handle and the `bytes` proof that authenticates it. Together they represent an encrypted value that can be used to reset the counter, and `FHE.asEuint64(value, inputProof)` converts the pair into a `euint64` the contract can compute on.

This value is an encrypted value that we created client-side using the SDK (read more about it [here](/client-sdk/guides/encrypting-inputs)).
Both come from the client, created with the SDK (read more about it [here](/client-sdk/guides/encrypting-inputs)).

### Decryption: Allow Public and Reveal

Expand All @@ -178,7 +178,7 @@ const countCtHash = await counter.counter();

const result = await client
.decryptForTx(countCtHash)
.withoutPermit()
.withoutACP()
.execute();
```

Expand Down Expand Up @@ -236,7 +236,7 @@ const countCtHash = await counter.get_encrypted_counter_value();

const result = await client
.decryptForView(countCtHash)
.withPermit()
.withACP()
.execute();

console.log(`Counter value (private): ${result.decryptedValue}`);
Expand Down
Loading