Skip to content

Commit

Permalink
docs: add fhevm/fundamentals
Browse files Browse the repository at this point in the history
  • Loading branch information
dartdart26 committed Aug 16, 2024
1 parent bf8a4a1 commit a811acb
Show file tree
Hide file tree
Showing 11 changed files with 269 additions and 36 deletions.
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ layout:

Learn the basics of fhEVM, set it up, and make it run with ease.

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="files"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Quick start</strong></td><td>Understand the basic concepts of fhEVM library.</td><td><a href=".gitbook/assets/start1.png">start1.png</a></td><td><a href="getting_started/quick_start.md">quick_start.md</a></td></tr><tr><td><strong>geth integration</strong></td><td>Use fhEVM with go-ethereum</td><td><a href=".gitbook/assets/start4.png">start4.png</a></td><td><a href="getting_started/fhevm/geth.md">geth.md</a></td></tr><tr><td><strong>Setup a Gateway</strong></td><td>Configure a Gateway to handle decryption and reecryption</td><td><a href=".gitbook/assets/start2.png">start2.png</a></td><td><a href="getting_started/gateway/configuration.md">configuration.md</a></td></tr><tr><td><strong>Use TKMS</strong></td><td>Use Zama's KMS with fhEVM</td><td><a href=".gitbook/assets/start5.png">start5.png</a></td><td><a href="getting_started/tkms/zama.md">zama.md</a></td></tr></tbody></table>
<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="files"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Quick start</strong></td><td>Understand the basic concepts of fhEVM library.</td><td><a href=".gitbook/assets/start1.png">start1.png</a></td><td><a href="getting_started/quick_start.md">quick_start.md</a></td></tr><tr><td><strong>geth integration</strong></td><td>Use fhEVM with go-ethereum</td><td><a href=".gitbook/assets/start4.png">start4.png</a></td><td><a href="getting_started/fhevm/geth.md">geth.md</a></td></tr><tr><td><strong>Setup a Gateway</strong></td><td>Configure a Gateway to handle decryption and reecryption</td><td><a href=".gitbook/assets/start2.png">start2.png</a></td><td><a href="getting_started/gateway/configuration.md">configuration.md</a></td></tr><tr><td><strong>Use TKMS</strong></td><td>Use Zama's TKMS with fhEVM</td><td><a href=".gitbook/assets/start5.png">start5.png</a></td><td><a href="getting_started/tkms/zama.md">zama.md</a></td></tr></tbody></table>

### References

Expand Down
5 changes: 2 additions & 3 deletions docs/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,14 @@
- [Use Zama's TKMS](getting_started/tkms/zama.md)
- [Request the creation of a new private key](getting_started/tkms/create.md)
- [Application Smart Contract](getting_started/tkms/contract.md)
- [Run a KMS](getting_started/tkms/run.md)
- [Run a TKMS](getting_started/tkms/run.md)

## Fundamentals

- [Architecture](fundamentals/overview.md)
- [Overview](fundamentals/overview.md)
- fhEVM
- [Architecture](fundamentals/fhevm/architecture.md)
- [Contracts](fundamentals/fhevm/contracts.md)
- [Backend](fundamentals/fhevm/backend.md)
- [Execution](fundamentals/fhevm/execution.md)
- [Storage](fundamentals/fhevm/storage.md)
- [Inputs](fundamentals/fhevm/inputs.md)
Expand Down
56 changes: 56 additions & 0 deletions docs/fundamentals/fhevm/architecture.md
Original file line number Diff line number Diff line change
@@ -1 +1,57 @@
# Architecture

The following diagram shows an fhEVM-native blockchain with 4 validators.

```mermaid
graph LR;
Validator1{{Validator1 Node}}
Validator1-- execution API ---Executor1
Executor1(Executor1)
Validator2{{Validator2 Node}}
Validator2-- execution API ---Executor2
Executor2(Executor2)
Validator3{{Validator3 Node}}
Validator3-- execution API ---Executor3
Executor3(Executor3)
Validator4{{Validator4 Node}}
Validator4-- execution API ---Executor4
Executor4(Executor4)
FullNode{{Full Node}}
FullNode-- execution API ---ExecutorFull
ExecutorFull(Executor F)
dApp[dApp]
fhevmjs[fhevmjs]
dApp-- uses ---fhevmjs
fhevmjs-- HTTP ---Gateway
fhevmjs-- RPC ---FullNode
Gateway(((Gateway)))
Gateway-- TKMS txns, events ---TKMS
Gateway-- RPC/WebSocket ---FullNode
TKMS[[TKMS]]
```

_Note:_ For brevity, we don't show P2P connections between validators and the full node in the diagram.

Each validator has two components:
* the validator node software that executes blocks and connects to other validators over the blockchain's P2P network
* the Executor that is responsible for the actual FHE computation

The Executor exposes an API that the validator node uses to send FHE computation requests.

A full node is similar to validators in the sense that it executes all blocks. The difference is that the full node doesn't have stake in the network and, therefore, cannot propose blocks. The full node has all the blockchain data locally. It can be used by the Gateway over RPC or WebSocket endpoints, allowing the Gateway to fetch storage proofs, fetch ciphertexts, listen for events on the fhEVM blockchain, etc.

The Gateway is a client from the TKMS' perspective and sends decryption/reencryption transactions, listens for "decryption ready" events, etc.

A dApp uses the **fhevmjs** library to interact with the fhEVM. Some examples are:
* connect over HTTP to the Gateway for reencryptions
* encrypt and decrypt data from the blockchain
* send transactions via a full node
* get the FHE public key from a full node

The TKMS is used to manage secret FHE key material and securely execute decryptions, reencryptions, key generation, etc. The TKMS is itself a blockchain. See [TKMS](../tkms/architecture.md).
1 change: 0 additions & 1 deletion docs/fundamentals/fhevm/backend.md

This file was deleted.

34 changes: 18 additions & 16 deletions docs/fundamentals/fhevm/contracts.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,39 @@
# Contracts

The fhEVM runs totally on chain symbolically. Essentially, inputs to FHE operations are symbolic values (also called handles) that refer to ciphertexts. We check constraints on these handles, but ignore their actual values.
The fhEVM employs symbolic execution - essentially, inputs to FHE operations are symbolic values (also called handles) that refer to ciphertexts. We check constraints on these handles, but ignore their actual values.

On the coprocessor, we actually execute the FHE operations on the ciphertexts the handles refer to. If a new ciphertext is generated in the coprocessor as a result of an FHE operation, it is inserted into the blockchain under a handle that is deterministically generated on both the blockchain and the coprocessor.
On the Executor, we actually execute the FHE operations on the ciphertexts the handles refer to. If a new ciphertext is generated in the Executor as a result of an FHE operation, it is inserted into the blockchain (into the ciphertext storage contract, see [Storage](storage.md)) under a handle that is deterministically generated in the TFHEExecutor contract.

## Coprocessor contract
## TFHEExecutor Contract

Symbolic execution on the blockchain is implemented via the [Coprocessor](https://github.com/zama-ai/fhevm/blob/main/lib/TFHEExecutor.sol) contract. One of the main responsibilites of the Coprocessor contract is to deterministically generate ciphertext handles. For this, we hash the FHE operation requested and the inputs to produce the result handle H:
Symbolic execution on the blockchain is implemented via the [TFHEExecutor](https://github.com/zama-ai/fhevm/blob/main/lib/TFHEExecutor.sol) contract. One of the main responsibilites of the TFHEExecutor contract is to deterministically generate ciphertext handles. For this, we hash the FHE operation requested and the inputs to produce the result handle H:

```
H = keccak256(2, fheOperation, input1, input2, ..., inputN)
H = keccak256(fheOperation, input1, input2, ..., inputN)
```

We use 2 as a domain separator for result handles.
Note that inputs can either be other handles or plaintext values. as described in FHE Execution and implemented in the newHandle() functions.
Inputs can either be other handles or plaintext values.

## ACL
_Note:_ As of now, TFHEExecutor emloys precompiles and not symbolic execution. It will soon be migrated to symbolic execution.

The [ACL](https://github.com/zama-ai/fhevm/blob/main/lib/ACL.sol) Contract enforces access control for ciphertexts. The model we adopt is very simple - a ciphertext is either allowed for an address or not. An address can be any address - either an EOA address or a contract address. We implement that via the pairs member variable. Essentially, it is a set of keccak256(handle, address) values, where the handle refers to a ciphertext. If a (handle, address) pair is in the set, the ciphertext the handle refers to can be used by the address. In Solidity, we implement the set as a mapping such that all values already in the mapping are true. Access control applies to both passing ciphertexts from one contract to another, for decryption and for reencryption of a ciphertext to a user-provided key.
## ACL Contract

We use keccak256(handle, address) in order to both save space by persisting only one value instead of two and, also, to allow for a single storage slot proof for reencryption.
The [ACL](https://github.com/zama-ai/fhevm/blob/main/lib/ACL.sol) contract enforces access control for ciphertexts. The model we adopt is very simple - a ciphertext is either allowed for an address or not. An address can be any address - either an EOA address or a contract address. Essentially, it is a mapping from handle to a set of addresses that are allowed to use the handle.

Access control applies to passing ciphertexts from one contract to another, for FHE computation on ciphertexts, for decryption and for reencryption of a ciphertext to a user-provided key.

### Garbage Collection of Allowed Ciphertexts Data

The pairs field in the ACL contract grows indefinitely as new ciphertexts are produced. We might want to expose ways for developers to reclaim space by marking that certain ciphertexts are no longer needed and, consequently, zeroing the slot in pairs. A future effort will look into that.
Data in the ACL contract grows indefinitely as new ciphertexts are produced. We might want to expose ways for developers to reclaim space by marking that certain ciphertexts are no longer needed and, consequently, zeroing the slot in the ACL. A future effort will look into that.

## Gateway Contract

## Gateway contract
The [Gateway](https://github.com/zama-ai/fhevm/blob/main/gateway/GatewayContract.sol) contract is an onchain contract designed to interact with an offchain Gateway component that handles decryption requests. When a dApp calls the `requestDecryption` function, the Gateway contract emits an event that is caught by the Gateway service.

The [Gateway](https://github.com/zama-ai/fhevm/blob/main/gateway/GatewayContract.sol) contract is an on-chain contract designed to interact with an off-chain oracle that handles decryption requests. When a dApp calls the `requestDecryption` function, the contract emits an event that is caught by the Gateway service.
Note: It is possible to have multiple Gateways, so multiple Gateway contracts can also be deployed.
_Note_: It is possible to have multiple Gateways, so multiple Gateway contracts can also be deployed.

## KMSVerifier contract
## KMSVerifier Contract

The [KMSVerifier](https://github.com/zama-ai/fhevm/blob/main/lib/KMSVerifier.sol) contract allows any dapp to verify a received decryption. This contract exposes a function `verifySignatures` which receives the decryption and signatures coming from the KMS.
The [KMSVerifier](https://github.com/zama-ai/fhevm/blob/main/lib/KMSVerifier.sol) contract allows any dApp to verify a received decryption. This contract exposes a function `verifySignatures` which receives the decryption and signatures coming from the TKMS.

Verifier addresses are stored and updated in the contract.
51 changes: 51 additions & 0 deletions docs/fundamentals/fhevm/execution.md
Original file line number Diff line number Diff line change
@@ -1 +1,52 @@
# Execution

Block execution in fhEVM-native is split into two parts:
* symbolic execution
* FHE computation

Symbolic execution happens onchain, inside the TFHEExecutor contract (inside the EVM). Essentially, the EVM accumulates all requested FHE operations in a block with their input handles and the corresponding result handles. It also remembers which result handles are stored via the SSTORE opcode. No FHE computations are done inside the EVM itself.

At the end of the block, the EVM sends a networking call to the Executor with the accumulated FHE computations. The Executor is free to do the FHE computations via any method, e.g. in parallel, on a cluster of compute nodes, via CPUs, GPUs, FPGAs or ASICs. The EVM waits until FHE computation for the block is done.

Finally, when results are returned to the EVM, it persists onchain the ciphertexts whose handles have been SSTOREd during symbolic execution. That way the EVM can avoid persisting ciphertexts that are intermediate results and are never actually stored by the smart contract developer.

```mermaid
sequenceDiagram
participant Node
participant Executor
loop Block Execution - Symbolic
Note over Node: Symbolic Execution on handles in Solidity
Note over Node: Inside EVM: computations.add(op, [inputs], [result_handles], [input_ciphertexts])
Note over Node: Inside EVM: if SSTORE(location, result) then sstored.add(result)
end
Note over Node: End of Block Execution
Node->>+Executor: SyncCompute (SyncComputeRequest(computations))
loop FHE Computation
Note over Executor: Read Inputs from SyncComputeRequest
Note over Executor: FHE Computation
end
Executor->>-Node: SyncComputeResponse (results)
Note over Node: Persist `sstored` Ciphertexts from `results` onchain
Note over Node: Commit Block
```

## Symbolic Execution

As mentioned, symbolic execution doesn't do any FHE computations. Instead, it only operates on input handles, checking constraints on them and deterministically producing result handles based on the input ones.

For more information on what symbolic execution does, please look at the [TFHEExecutor](https://github.com/zama-ai/fhevm/blob/main/lib/TFHEExecutor.sol) contract.

## Interaction with the TFHEExecutor Contract

The TFHEExecutor contract is deployed when the chain is created and is at a well-known address that is also known by blockchain nodes. When a node (validator or full node) detects a call to this address (a CALL or STATITCCALL opcode), the EVM running in the node looks at the function signature and determines which FHE computation is being requested. The result handle is the result of this particular call to the TFHEExecutor contract and the EVM can accumulate it in the computations list for the block.

## FHE Computation Data Dependencies

Note that the EVM sends both input handles and result handles to the Executor. It is able to do that, because result handles are computed symbolically in the TFHEExecutor contract. That allows the Executor to do parallel FHE computation by analysing which computations are independent.

The Executor can detect a conflict if an output of computation A (or the output of another computation depending on the output of A) is also used as an input in a subsequent computation B. We call these computations `dependent` and we need to execute them in order.

On the other hand, if two computations have inputs that are not related to their outputs, we call them `independent` and the Executor can schedule them to run in parallel.
10 changes: 10 additions & 0 deletions docs/fundamentals/fhevm/genesis.md
Original file line number Diff line number Diff line change
@@ -1 +1,11 @@
# Genesis

## Contracts

For an fhEVM-native blockchain to operate and execute FHE computations, certain contracts need to be available when creating the chain - see [Contracts](contracts.md). Strictly speaking, these contracts don't have to be available in the genesis block and can be deployed in the second block of the chain, at runtime.

## Keys

FHE-related keys need to available for the chain to operate properly. For example, a public FHE execution key is needed at the Executor to be able to compute on encrypted data.

As a convenience, the FHE public key can also be stored on validators/full nodes.
45 changes: 45 additions & 0 deletions docs/fundamentals/fhevm/inputs.md
Original file line number Diff line number Diff line change
@@ -1 +1,46 @@
# Inputs

When we talk about inputs, we refer to encrypted data the users send to the fhEVM-native blockchain. Data is in the form of FHE ciphertexts. An example would be the amount to be transferred when calling an ERC20 transfer function.

## ZKPoK
It is important that confidential data sent by users cannot be seen by anyone. Without measures, there are multiple ways that could happen, for example:
* anyone decrypting the ciphertext
* anyone doing arbitrary computations via the ciphertext (e.g. adding 0 to it), producing a new ciphertext that itself is decrypted (including malicious actors using ciphertexts of other users)
* using the ciphertext in a malicious contract that leads to decryption

Furthermore, if users are allowed to send arbitrary ciphertexts (including malformed ones or maliciously-crafted ones), that could lead to revealing data about the FHE secret key.

Therefore, we employ zero-knowledge proofs of knowledge (ZKPoK) of input FHE ciphertexts that guarantee:

* ciphertext is well-formed (i.e. encryption has been done correctly)
* the user knows the plaintext value
* the input ciphertext can only be used in a particular smart contract

The ZKPoK is verified by validator nodes when the input byte array is passed to an `TFHE.asEuintXX()` function to convert from a ciphertext to a handle that can be used in smart contracts for FHE operations.

## Compact Input Lists

To greatly reduce the size of FHE ciphertexts inputs, we utilize a feature called compact lists. It allows us to pack multiple values efficiently. It is useful when there is only one input and even more so when the are multiple inputs in a call to a smart contract.

We define the `einput` type that refers to a particular ciphertext in the list. The list itself is serialized and passed as a byte array. For example, `inputA` and `inputB` refer to ciphertexts in the list and the serialized list is `inputProof`:

```solidity
// SPDX-License-Identifier: BSD-3-Clause-Clear
pragma solidity ^0.8.24;
import "fhevm/lib/TFHE.sol";
contract Adder {
euint32 result;
function add(einput inputA, einput inputB, bytes calldata inputProof) public {
euint32 a = TFHE.asEuint32(inputA, inputProof);
euint32 b = TFHE.asEuint32(inputB, inputProof);
result = TFHE.add(a, b);
TFHE.allow(result, address(this));
}
}
```

Note that `inputProof` also contains the ZKPoK.
Loading

0 comments on commit a811acb

Please sign in to comment.