From 713a5e1553bba3e34a3f8d59f610cf0459adee1f Mon Sep 17 00:00:00 2001 From: Aurora Poppyseed <30662672+poppyseedDev@users.noreply.github.com> Date: Thu, 28 Nov 2024 14:49:20 +0100 Subject: [PATCH] docs: add review --- README.md | 31 +--- docs/README.md | 9 +- docs/SUMMARY.md | 6 +- docs/fundamentals/first_step/acl_examples.md | 10 +- docs/fundamentals/first_step/configure.md | 136 ++++++++------- docs/fundamentals/first_step/decrypt.md | 29 ++-- .../first_step/decrypt_details.md | 7 +- docs/fundamentals/first_step/index.md | 77 +++++++++ docs/fundamentals/first_step/inputs.md | 23 ++- docs/fundamentals/first_step/operations.md | 79 +++++++++ docs/fundamentals/first_step/reencryption.md | 7 +- docs/fundamentals/first_step/start.md | 65 +++++++- docs/fundamentals/first_step/types.md | 3 +- docs/guides/contracts.md | 73 ++++++++ docs/guides/loop.md | 66 ++++++++ docs/guides/pitfalls.md | 156 ------------------ docs/tutorials/see-all-tutorials.md | 36 ++-- 17 files changed, 506 insertions(+), 307 deletions(-) create mode 100644 docs/fundamentals/first_step/index.md create mode 100644 docs/guides/contracts.md delete mode 100644 docs/guides/pitfalls.md diff --git a/README.md b/README.md index d670ebe4..2cfb8a7d 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ _Learn more use cases in the [list of examples](https://docs.zama.ai/fhevm/tutor - [A Simple Example](#a-simple-example) - **[Resources](#resources)** - [White paper](#white-paper) - - [Demos](#demos) +[Demos](#demos-and-tutorials) - [Tutorials](#tutorials) - [Documentation](#documentation) - [Blockchain Implementation](#blockchain-implementation) @@ -142,34 +142,9 @@ _More examples are available [here](https://github.com/zama-ai/fhevm/tree/main/e - [Confidential EVM Smart Contracts using Fully Homomorphic Encryption](https://github.com/zama-ai/fhevm/blob/main/fhevm-whitepaper.pdf)

-### Demos +### Demos and Tutorials -#### Finance - -- [ERC-20](https://github.com/zama-ai/fhevm/blob/main/examples/EncryptedERC20.sol): A variation of the standard ERC20 smart contract that incorporates encrypted balances, providing additional privacy for token holders. -- [Darkpool](https://github.com/omurovec/fhe-darkpools): A smart contract that enables anonymous trading of cryptocurrencies or assets, typically used to execute large orders without affecting the market price. - by [Owen Murovec](https://github.com/omurovec) - -#### Games: - -- [Cipherbomb](https://github.com/immortal-tofu/cipherbomb): A Hardhat-based template for developing Solidity smart contracts, with sensible defaults. - by Clément Danjou -- [Battleship](https://github.com/battleship-fhevm/battleship-hardhat): A smart contract that replicates the classic Battleship game on a blockchain in a transparent manner. - by [Owen Murovec](https://github.com/omurovec) - -#### Others - -- [Blind auction](https://github.com/zama-ai/fhevm/blob/main/examples/BlindAuction.sol): A smart contract for conducting blind auctions where bids are encrypted and the winning bid remains private. - -_If you have built awesome projects using fhEVM, please let us know and we will be happy to showcase them here!_ -

- -### Tutorials - -- [[Video tutorial] How to Write Confidential Smart Contracts Using Zama's fhEVM](https://www.zama.ai/post/video-tutorial-how-to-write-confidential-smart-contracts-using-zamas-fhevm) -- [Confidential ERC-20 Tokens Using Homomorphic Encryption and the fhEVM](https://www.zama.ai/post/confidential-erc-20-tokens-using-homomorphic-encryption) -- [On-chain Blind Auctions Using Homomorphic Encryption and the fhEVM](https://www.zama.ai/post/on-chain-blind-auctions-using-homomorphic-encryption) -- [Programmable Privacy and Onchain Compliance using Homomorphic Encryption](https://www.zama.ai/post/programmable-privacy-and-onchain-compliance-using-homomorphic-encryption) - -_Explore more useful resources in [fhEVM tutorials](https://docs.zama.ai/fhevm/tutorials/see-all-tutorials) and [Awesome Zama repo](https://github.com/zama-ai/awesome-zama)._ -

+For a comprehensive list of demos and tutorials, visit our [tutorials page](https://docs.zama.ai/fhevm/tutorials/see-all-tutorials). ### Documentation diff --git a/docs/README.md b/docs/README.md index 736cfcc9..fd9c403d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -21,13 +21,13 @@ layout: Learn the basics of fhEVM, set it up, and make it run with ease. -
What is fhEVMUnderstand the basic concepts of fhEVM library.start1.pngoverview.md
Write contractStart writing fhEVM smart contract using Hardhat templatestart4.pnghardhat.md
Deploy on fhEVM nativeGet 10 Zama token to start working with fhEVM nativestart2.pngdevnet.md
Deploy on EthereumComing soon!start5.pngethereum.md
+
What is fhEVMUnderstand the basic concepts of fhEVM library.start1.pngoverview.md
Write contractStart writing fhEVM smart contract using Hardhat templatestart4.pnghardhat.md
Learn to write FHE contractsLearn how to write your first confidential smart contractstart2.pngstart.md
Deploy on EthereumBe one of the first to deploy confidential smart contracts on Ethereum!start5.pngethereum.md
## Develop a fhEVM smart contract Start developing fhEVM smart contracts in Solidity by exploring its core features, discovering essential guides, and learning more with user-friendly tutorials. -
FundamentalsExplore core features.build1.png
GuidesDeploy your project.build2.png
TutorialsLearn more with tutorials.build3.png
+
FundamentalsExplore core features.build1.png
GuidesLearn further.build2.png
TutorialsLearn more with tutorials.build3.png
## Explore more @@ -55,8 +55,9 @@ Collaborate with us to advance the FHE spaces and drive innovation together. - [Contribute to fhEVM](developer/contribute.md) - [Follow the development roadmap](developer/roadmap.md) - [See the latest test release note](https://github.com/zama-ai/fhevm/releases) -- [Request a feature](https://github.com/zama-ai/fhevm/issues/new) -- [Report a bug](https://github.com/zama-ai/fhevm/issues/new) +- [Request a feature](https://github.com/zama-ai/fhevm/issues/new?assignees=&labels=enhancement&projects=&template=feature-request.md&title=) +- [Report a bug](https://github.com/zama-ai/fhevm/issues/new?assignees=&labels=bug&projects=&template=bug_report_fhevm.md&title=) + --- diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 64fe8626..f0ae60e5 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -19,7 +19,8 @@ - [Architecture overview](fundamentals/architecture_overview.md) - [Encryption, decryption, re-encryption, and computation](fundamentals/d_re_ecrypt_compute.md) - [Access control list](fundamentals/acl.md) -- [Configuration](fundamentals/first_step/configure.md) +- [Workflow for SC development](fundamentals/first_step/index.md) + - [Configuration](fundamentals/first_step/configure.md) - [First smart contract](fundamentals/first_step/start.md) - [Supported types](fundamentals/first_step/types.md) - [Operations on encrypted types](fundamentals/first_step/operations.md) @@ -32,11 +33,10 @@ ## Guides - Smart Contracts - - [Common pitfalls and best practises](guides/pitfalls.md) + - [fhevm-contracts](guides/contracts.md) - [If sentances](guides/loop.md) - [Branching in FHE](guides/conditions.md) - [Generate random numbers](guides/random.md) - - [Gas estimation on devnet](guides/gas.md) - [Error handling](guides/error_handling.md) - Frontend - [Build a web application](guides/frontend/webapp.md) diff --git a/docs/fundamentals/first_step/acl_examples.md b/docs/fundamentals/first_step/acl_examples.md index 9bbeb9b6..f6b630a6 100644 --- a/docs/fundamentals/first_step/acl_examples.md +++ b/docs/fundamentals/first_step/acl_examples.md @@ -33,12 +33,12 @@ The ACL system allows you to define two types of permissions for accessing ciphe ```solidity import "fhevm/lib/TFHE.sol"; +import { MockZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; -contract SecretGiver { +contract SecretGiver is MockZamaFHEVMConfig { SecretStore public secretStore; constructor() { - TFHE.setFHEVM(FHEVMConfig.defaultConfig()); secretStore = new SecretStore(); } @@ -53,8 +53,10 @@ contract SecretGiver { secretStore.storeSecret(mySecret); } } +``` -contract SecretStore { +``` +contract SecretStore is MockZamaFHEVMConfig { euint16 public secretResult; function storeSecret(euint16 callerSecret) public { @@ -100,7 +102,7 @@ function randomize() public { --- -## Security best practices +## 🔧 Best practices ### Verifying sender access diff --git a/docs/fundamentals/first_step/configure.md b/docs/fundamentals/first_step/configure.md index 7738bd96..f38d3f29 100644 --- a/docs/fundamentals/first_step/configure.md +++ b/docs/fundamentals/first_step/configure.md @@ -1,96 +1,116 @@ -# Configuring your smart contract for encrypted computations +# Configuring Your Smart Contract for Encrypted Computations -This document describes how to enable encrypted computations in your smart contract by setting up the `fhEVM` environment. This involves configuring essential functions and integrating specific libraries to handle encrypted data securely and efficiently. +This document explains how to enable encrypted computations in your smart contract by setting up the `fhEVM` environment. Learn how to integrate essential libraries, configure encryption, and add secure computation logic to your contracts. --- -## Workflow for writing confidential smart contracts +## Core Configuration Setup -1. **Use the Hardhat Template**: - Start with our custom [`fhevm-hardhat-template` repository](https://github.com/zama-ai/fhevm-hardhat-template). Hardhat is a powerful development environment for Solidity, allowing you to write, test, and deploy contracts to the `fhEVM` using TypeScript. +To utilize encrypted computations in Solidity contracts, you must configure the **TFHE library** and **Gateway addresses**. The `fhevm` package simplifies this process with prebuilt configuration contracts, allowing you to focus on developing your contract’s logic without handling the underlying cryptographic setup. -2. **Begin with Unencrypted Logic**: - Develop your contract as if it were intended for a traditional EVM chain. Use cleartext variables and basic logic, which simplifies reasoning about the contract’s functionality. +### Key Components Configured Automatically: +1. **TFHE Library**: Sets up encryption parameters and cryptographic keys. +2. **Gateway**: Manages secure cryptographic operations, including reencryption and decryption. +3. **Network-Specific Settings**: Adapts to local testing, testnets (e.g., Sepolia), or mainnet deployment. -3. **Add Encryption**: - Integrate the `TFHE` Solidity library to enable encryption. Convert sensitive variables (e.g., `uintX`) into encrypted types (e.g., `euintX`) to ensure confidentiality. Refer to the [pitfalls to avoid and best practices](../../guides/pitfalls.md) guide for detailed advice. - -4. **Leverage Example Templates**: - The [fhevm-contracts repository](https://github.com/zama-ai/fhevm-contracts) provides a collection of example smart contracts demonstrating common FHE patterns and best practices. Use these templates to: - - Study proven implementation patterns - - Understand gas optimization techniques - - Learn how to properly handle encrypted operations - - See real-world examples of confidential smart contracts +By inheriting these configuration contracts, you ensure seamless initialization and functionality across environments. --- -## Core configuration functions - -Below are the key configuration functions needed to enable encrypted operations in your contract. +### ZamaFHEVMConfig.sol -### `setFHEVM` - -This function initializes the FHEVM environment with the required configuration. +This configuration contract initializes the **FHEVM environment** with required encryption parameters. +#### Import Based on Your Environment: ```solidity -function setFHEVM(FHEVMConfig.FHEVMConfigStruct memory fhevmConfig) public -``` +// For Mock testnet +import { MockZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; + +// For Ethereum Sepolia +import { SepoliaZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; -- **Purpose**: Sets encryption parameters, including cryptographic keys and supported ciphertext types. -- **Usage**: Call this function in the constructor to ensure proper initialization. -- **Default Configuration**: Use `FHEVMConfig.defaultConfig()` for a standard encryption setup. +// For Ethereum Mainnet (when ready) +import { EthereumZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; +``` -#### Example +#### Purpose: +- Sets encryption parameters such as cryptographic keys and supported ciphertext types. +- Ensures proper initialization of the FHEVM environment. +#### Example: Using Mock Configuration ```solidity -constructor() { - // Initialize the FHEVM environment with default settings - TFHE.setFHEVM(FHEVMConfig.defaultConfig()); +// SPDX-License-Identifier: BSD-3-Clause-Clear +pragma solidity ^0.8.24; + +import { MockZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; + +contract MyERC20 is MockZamaFHEVMConfig { + constructor() { + // Additional initialization logic if needed + } } -``` +``` --- -### `isInitialized` +### ZamaGatewayConfig.sol -This utility function verifies whether a given encrypted variable is initialized. +To perform decryption or reencryption, your contract must interact with the **Gateway**, which acts as a secure bridge between the blockchain, coprocessor, and Key Management System (KMS). +#### Import Based on Your Environment: ```solidity -function isInitialized(T v) internal pure returns (bool) -``` +// For Mock testnet +import { MockZamaGatewayConfig } from "fhevm/config/ZamaGatewayConfig.sol"; + +// For Ethereum Sepolia +import { SepoliaZamaGatewayConfig } from "fhevm/config/ZamaGatewayConfig.sol"; -- **Purpose**: Prevents uninitialized encrypted variables from being used, avoiding unexpected behavior. -- **Usage**: Use this check in critical functions or constructors. +// For Ethereum Mainnet (when ready) +import { EthereumZamaGatewayConfig } from "fhevm/config/ZamaGatewayConfig.sol"; +``` -#### Example +#### Purpose: +- Configures the Gateway for secure cryptographic operations. +- Facilitates reencryption and decryption requests. +#### Example: Configuring the Gateway with Mock Settings ```solidity -require(TFHE.isInitialized(counter), "Counter not initialized!"); -``` +import "fhevm/lib/TFHE.sol"; +import { MockZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; +import { MockZamaGatewayConfig } from "fhevm/config/ZamaGatewayConfig.sol"; +import "fhevm/gateway/GatewayCaller.sol"; + +contract Test is MockZamaFHEVMConfig, MockZamaGatewayConfig, GatewayCaller { + constructor() { + // Gateway and FHEVM environment initialized automatically + } +} +``` --- -### `setGateway` +### Using `isInitialized` -When performing decryption or re-encryption, you must configure the contract to interact with the `Gateway`. +The `isInitialized` utility function checks whether an encrypted variable has been properly initialized, preventing unexpected behavior due to uninitialized values. +#### Function Signature: ```solidity -Gateway.setGateway(Gateway.defaultGatewayAddress()); -``` - -The Gateway serves as the bridge between the blockchain, coprocessor, and KMS for secure cryptographic operations. +function isInitialized(T v) internal pure returns (bool) +``` -#### Example +#### Purpose: +- Ensures encrypted variables are initialized before use. +- Prevents potential logic errors in contract execution. +#### Example: Initialization Check for Encrypted Counter ```solidity -import "fhevm/lib/TFHE.sol"; -import "fhevm/gateway/GatewayCaller.sol"; +require(TFHE.isInitialized(counter), "Counter not initialized!"); +``` -contract Test is GatewayCaller { - constructor() { - // Set up the FHEVM and Gateway configurations - TFHE.setFHEVM(FHEVMConfig.defaultConfig()); - Gateway.setGateway(Gateway.defaultGatewayAddress()); - } -} -``` +--- + +## Summary + +By leveraging prebuilt configuration contracts like `ZamaFHEVMConfig.sol` and `ZamaGatewayConfig.sol`, you can efficiently set up your smart contract for encrypted computations. These tools abstract the complexity of cryptographic initialization, allowing you to focus on building secure, confidential smart contracts. + +For a complete guide on contract development and integration, refer to our [Workflow for Writing Confidential Smart Contracts](../../guides/workflow.md). \ No newline at end of file diff --git a/docs/fundamentals/first_step/decrypt.md b/docs/fundamentals/first_step/decrypt.md index 9f30cd10..25dbb73d 100644 --- a/docs/fundamentals/first_step/decrypt.md +++ b/docs/fundamentals/first_step/decrypt.md @@ -33,16 +33,15 @@ Here’s an example of how to request decryption in a contract: pragma solidity ^0.8.24; import "fhevm/lib/TFHE.sol"; +import { MockZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; +import { MockZamaGatewayConfig } from "fhevm/config/ZamaGatewayConfig.sol"; import "fhevm/gateway/GatewayCaller.sol"; -contract TestAsyncDecrypt is GatewayCaller { +contract TestAsyncDecrypt is MockZamaFHEVMConfig, MockZamaGatewayConfig, GatewayCaller { ebool xBool; bool public yBool; constructor() { - TFHE.setFHEVM(FHEVMConfig.defaultConfig()); - Gateway.setGateway(Gateway.defaultGatewayAddress()); - xBool = TFHE.asEbool(true); TFHE.allowThis(xBool); } @@ -61,21 +60,20 @@ contract TestAsyncDecrypt is GatewayCaller { ### Key additions to the code -1. **`GatewayCaller` import**: - The `GatewayCaller` contract is imported to enable decryption requests. +1. **Configuration imports**: + The configuration contracts are imported to set up the FHEVM environment and Gateway. ```solidity - import "fhevm/gateway/GatewayCaller.sol"; + import { MockZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; + import { MockZamaGatewayConfig } from "fhevm/config/ZamaGatewayConfig.sol"; ``` -2. **`Gateway.setGateway` function**: - This function sets the address of the Gateway contract, which processes decryption requests. It is typically called in the constructor: + +2. **`GatewayCaller` import**: + The `GatewayCaller` contract is imported to enable decryption requests. ```solidity - constructor() { - TFHE.setFHEVM(FHEVMConfig.defaultConfig()); - Gateway.setGateway(Gateway.defaultGatewayAddress()); - } + import "fhevm/gateway/GatewayCaller.sol"; ``` ## Applying decryption to the counter example @@ -87,19 +85,20 @@ Remember our **Encrypted Counter** contract from before? Here’s an improved ve pragma solidity ^0.8.24; import "fhevm/lib/TFHE.sol"; +import { MockZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; +import { MockZamaGatewayConfig } from "fhevm/config/ZamaGatewayConfig.sol"; import "fhevm/gateway/GatewayCaller.sol"; /// @title EncryptedCounter3 /// @notice A contract that maintains an encrypted counter and is meant for demonstrating how decryption works /// @dev Uses TFHE library for fully homomorphic encryption operations and Gateway for decryption /// @custom:experimental This contract is experimental and uses FHE technology with decryption capabilities -contract EncryptedCounter3 is GatewayCaller { +contract EncryptedCounter3 is MockZamaFHEVMConfig, MockZamaGatewayConfig, GatewayCaller { /// @dev Decrypted state variable euint8 counter; uint8 public decryptedCounter; constructor() { - TFHE.setFHEVM(FHEVMConfig.defaultConfig()); Gateway.setGateway(Gateway.defaultGatewayAddress()); // Initialize counter with an encrypted zero value diff --git a/docs/fundamentals/first_step/decrypt_details.md b/docs/fundamentals/first_step/decrypt_details.md index 7dc6f040..dbd80f7b 100644 --- a/docs/fundamentals/first_step/decrypt_details.md +++ b/docs/fundamentals/first_step/decrypt_details.md @@ -114,16 +114,15 @@ For example, see this snippet where we add two `uint256`s during the request cal pragma solidity ^0.8.24; import "fhevm/lib/TFHE.sol"; +import { MockZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; +import { MockZamaGatewayConfig } from "fhevm/config/ZamaGatewayConfig.sol"; import "fhevm/gateway/GatewayCaller.sol"; -contract TestAsyncDecrypt is GatewayCaller { +contract TestAsyncDecrypt is MockZamaFHEVMConfig, MockZamaGatewayConfig, GatewayCaller { euint32 xUint32; uint32 public yUint32; constructor() { - TFHE.setFHEVM(FHEVMConfig.defaultConfig()); - Gateway.setGateway(Gateway.defaultGatewayAddress()); - xUint32 = TFHE.asEuint32(32); TFHE.allowThis(xUint32); } diff --git a/docs/fundamentals/first_step/index.md b/docs/fundamentals/first_step/index.md new file mode 100644 index 00000000..890f3306 --- /dev/null +++ b/docs/fundamentals/first_step/index.md @@ -0,0 +1,77 @@ +# Workflow for writing confidential smart contracts + +This document outlines the essential steps for developing secure and efficient confidential smart contracts using `fhEVM`. By following this workflow, you can streamline the process and ensure best practices are implemented throughout your project. + +## Step-by-Step Workflow + +### 1. Use the Hardhat template +Begin with our custom [`fhevm-hardhat-template` repository](https://github.com/zama-ai/fhevm-hardhat-template). +- **Why Hardhat?**: It is a powerful Solidity development environment, offering tools for writing, testing, and deploying contracts to the `fhEVM` using TypeScript. +- **Benefit**: The template provides a pre-configured setup tailored to confidential smart contracts, saving development time and ensuring compatibility. + +--- + +### 2. Configure the contract +Choose and inherit the correct configuration based on the environment: +- **Mock Network**: For local testing and development. +- **Testnets (e.g., Sepolia)**: For deploying to public test networks. +- **Mainnet**: When deploying to production. + +Ensure configuration contracts (e.g., `MockZamaFHEVMConfig`, `SepoliaZamaFHEVMConfig`) are inherited correctly to initialize encryption parameters, cryptographic keys, and Gateway addresses. + +--- + +### 3. Begin with unencrypted Logic +Develop your contract as you would for a traditional EVM chain: +- Use cleartext variables and basic logic to simplify debugging and reasoning about the contract’s behavior. +- Focus on implementing core functionality without adding encryption initially. + +--- + +### 4. Add Encryption +Once the logic is stable, integrate the `TFHE` Solidity library to enable encryption: +- **Convert Sensitive Variables**: Replace plaintext types like `uintX` with encrypted types such as `euintX`. +- **Enable Confidentiality**: Encrypted variables and operations ensure sensitive data remains private while still being processed. + +--- + +### 5. Follow best practices +Throughout the documentation, you'll find sections marked with 🔧 that highlight important best practices. These include: + +🔧 **Optimized Data Types** +- Use appropriately sized encrypted types (`euint8`, `euint16`, etc.) to minimize gas costs. + +🔧 **Scalar Operands** +- Whenever possible, use scalar operands in operations to reduce computation and gas usage. + +🔧 **Overflow Handling** +- Manage arithmetic overflows in encrypted operations using conditional logic (`TFHE.select`). + +🔧 **Secure Access Control** +- Use `TFHE.allow` and `TFHE.isSenderAllowed` to implement robust ACL (Access Control List) mechanisms for encrypted values. + +🔧 **Reencryption Patterns** +- Follow the recommended approaches for reencryption to share or repurpose encrypted data securely. + +--- + +### 6. Leverage example templates +Use the [`fhevm-contracts repository`](https://github.com/zama-ai/fhevm-contracts) for pre-built examples: +- **Why Templates?**: They demonstrate common patterns and best practices for encrypted operations, such as governance, token standards, and utility contracts. +- **How to Use**: Extend or customize these templates to suit your application’s needs. + +For more details, explore the [fhevm-contracts documentation](../../guides/contracts.md). + +## Contract examples + +Throughout these tutorials, you'll learn how to write secure confidential smart contracts using fhEVM. We'll use practical examples to demonstrate key concepts and best practices. + +Our main example will be a `Counter.sol` contract that we'll progressively enhance to showcase: + +- Basic encrypted state variables and operations +- Access control mechanisms +- Secure computation patterns +- Interaction between encrypted and unencrypted data +- Advanced FHE features and optimizations + +Each iteration of the counter will build upon previous concepts while introducing new functionality, helping you understand how to develop robust confidential smart contracts. \ No newline at end of file diff --git a/docs/fundamentals/first_step/inputs.md b/docs/fundamentals/first_step/inputs.md index 433fd044..3391b22a 100644 --- a/docs/fundamentals/first_step/inputs.md +++ b/docs/fundamentals/first_step/inputs.md @@ -1,4 +1,4 @@ -# Encryption and Encrypted Inputs in fhEVM +# Encryption and encrypted inputs in fhEVM This document introduces the concept of encrypted inputs in the fhEVM, explaining their role, structure, validation process, and how developers can integrate them into smart contracts and applications. @@ -6,17 +6,17 @@ This document introduces the concept of encrypted inputs in the fhEVM, explainin Encrypted inputs are a core feature of fhEVM, enabling users to push encrypted data onto the blockchain while ensuring data confidentiality and integrity. -## What Are Encrypted Inputs? +## What are encrypted inputs? Encrypted inputs are data values submitted by users in ciphertext form. These inputs allow sensitive information to remain confidential while still being processed by smart contracts. They are accompanied by **Zero-Knowledge Proofs of Knowledge (ZKPoKs)** to ensure the validity of the encrypted data without revealing the plaintext. -### **Key Characteristics of Encrypted Inputs**: +### Key characteristics of encrypted inputs: 1. **Confidentiality**: Data is encrypted using the public FHE key, ensuring that only authorized parties can decrypt or process the values. 2. **Validation via ZKPoKs**: Each encrypted input is accompanied by a proof verifying that the user knows the plaintext value of the ciphertext, preventing replay attacks or misuse. 3. **Efficient Packing**: All inputs for a transaction are packed into a single ciphertext in a user-defined order, optimizing the size and generation of the zero-knowledge proof. -## Parameters in Encrypted Functions +## Parameters in encrypted functions When a function in a smart contract is called, it may accept two types of parameters for encrypted inputs: @@ -41,7 +41,7 @@ function myExample( In this example, `param1`, `param2`, and `param3` are encrypted inputs, while `inputProof` contains the corresponding ZKPoK to validate their authenticity. -## Client-Side Implementation +## Client-Side implementation To interact with such a function, developers can use the [fhevmjs](https://github.com/zama-ai/fhevmjs) library to create and manage encrypted inputs. Below is an example implementation: @@ -74,11 +74,11 @@ In this example: - **`add64`, `addBool`, and `add8`**: Specify the types and values of inputs to encrypt. - **`encrypt`**: Generates the encrypted inputs and the zero-knowledge proof. -## Validating Encrypted Inputs +## Validating encrypted inputs Smart contracts process encrypted inputs by verifying them against the associated zero-knowledge proof. This is done using the `TFHE.asEuintXX`, `TFHE.asEbool`, or `TFHE.asEaddress` functions, which validate the input and convert it into the appropriate encrypted type. -### Example Validation that goes along the Client-Side implementation +### Example validation that goes along the client-Side implementation This example demonstrates a function that performs multiple encrypted operations, such as updating a user's encrypted balance and toggling an encrypted boolean flag: @@ -111,7 +111,7 @@ This example demonstrates a function that performs multiple encrypted operations } ``` -### Example Validation in the `encyrptedERC20.sol` Smart Contract +### Example validation in the `encyrptedERC20.sol` smart contract Here’s an example of a smart contract function that verifies an encrypted input before proceeding: @@ -138,7 +138,7 @@ function transfer( --- -## **Best Practices** +## 🔧 Best Practices - **Input Packing**: Minimize the size and complexity of zero-knowledge proofs by packing all encrypted inputs into a single ciphertext. - **Frontend Encryption**: Always encrypt inputs using the FHE public key on the client side to ensure data confidentiality. @@ -155,6 +155,7 @@ Now that we have new knowledge on how to add encrypted inputs, let's upgrade our pragma solidity ^0.8.24; import "fhevm/lib/TFHE.sol"; +import { MockZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; /// @title EncryptedCounter2 /// @notice A contract that maintains an encrypted counter and is meant for demonstrating how to add encrypted types @@ -163,9 +164,7 @@ import "fhevm/lib/TFHE.sol"; contract EncryptedCounter2 { euint8 counter; - constructor() { - TFHE.setFHEVM(FHEVMConfig.defaultConfig()); - + constructor() is MockZamaFHEVMConfig { // Initialize counter with an encrypted zero value counter = TFHE.asEuint8(0); TFHE.allowThis(counter); diff --git a/docs/fundamentals/first_step/operations.md b/docs/fundamentals/first_step/operations.md index 95102377..490eb95c 100644 --- a/docs/fundamentals/first_step/operations.md +++ b/docs/fundamentals/first_step/operations.md @@ -81,6 +81,85 @@ euint64 b = TFHE.asEuint64(58); euint64 sum = a + b; // Calls TFHE.add under the hood ``` +## 🔧 Best Practices +Here are some best practices to follow when using encrypted operations in your smart contracts: + +### Use the appropriate encrypted type size + +Choose the smallest encrypted type that can accommodate your data to optimize gas costs. For example, use `euint8` for small numbers (0-255) rather than `euint256`. + +❌ Avoid using oversized types: + +```solidity +// Bad: Using euint256 for small numbers wastes gas +euint64 age = TFHE.euint256(25); // age will never exceed 255 +euint64 percentage = TFHE.euint256(75); // percentage is 0-100 +``` + +✅ Instead, use the smallest appropriate type: + +```solidity +// Good: Using appropriate sized types +euint8 age = TFHE.asEuint8(25); // age fits in 8 bits +euint8 percentage = TFHE.asEuint8(75); // percentage fits in 8 bits +``` + +### Use scalar operands when possible to save gas + +Some TFHE operators exist in two versions : one where all operands are ciphertexts handles, and another where one of the operands is an unencrypted scalar. Whenever possible, use the scalar operand version, as this will save a lot of gas. See the page on [Gas](gas.md) to discover which operators support scalar operands and compare the gas saved between both versions: all-encrypted operands vs scalar. + +❌ For example, this snippet cost way more in gas: + +```solidity +euint32 x; +... +x = TFHE.add(x,TFHE.asEuint(42)); +``` + +✅ Than this one: + +```solidity +euint32 x; +// ... +x = TFHE.add(x,42); +``` + +Despite both leading to the same encrypted result! + +### Beware of overflows of TFHE arithmetic operators + +TFHE arithmetic operators can overflow. Do not forget to take into account such a possibility when implementing fhEVM smart contracts. + +❌ For example, if you wanted to create a mint function for an encrypted ERC20 tokens with an encrypted `totalSupply` state variable, this code is vulnerable to overflows: + +```solidity +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.allowThis(balances[msg.sender]); + TFHE.allow(balances[msg.sender], msg.sender); +} +``` + +✅ But you can fix this issue by using `TFHE.select` to cancel the mint in case of an overflow: + +```solidity +function mint(einput encryptedAmount, bytes calldata inputProof) public { + euint32 mintedAmount = TFHE.asEuint32(encryptedAmount, inputProof); + euint32 tempTotalSupply = TFHE.add(totalSupply, mintedAmount); + ebool isOverflow = TFHE.lt(tempTotalSupply, totalSupply); + 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.allowThis(balances[msg.sender]); + TFHE.allow(balances[msg.sender], msg.sender); +} +``` + +Notice that we did not check separately the overflow on `balances[msg.sender]` but only on `totalSupply` variable, because `totalSupply` is the sum of the balances of all the users, so `balances[msg.sender]` could never overflow if `totalSupply` did not. + + ## Additional Resources - For detailed API specifications, visit the [fhEVM API Documentation](../../references/functions.md). diff --git a/docs/fundamentals/first_step/reencryption.md b/docs/fundamentals/first_step/reencryption.md index 63b8f46b..a90cc944 100644 --- a/docs/fundamentals/first_step/reencryption.md +++ b/docs/fundamentals/first_step/reencryption.md @@ -112,20 +112,17 @@ Here’s an enhanced **Encrypted Counter** example where each user maintains the pragma solidity ^0.8.24; import "fhevm/lib/TFHE.sol"; +import { MockZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; /// @title EncryptedCounter4 /// @notice A contract that maintains encrypted counters for each user and is meant for demonstrating how re-encryption works /// @dev Uses TFHE library for fully homomorphic encryption operations /// @custom:security Each user can only access and modify their own counter /// @custom:experimental This contract is experimental and uses FHE technology -contract EncryptedCounter4 { +contract EncryptedCounter4 is MockZamaFHEVMConfig { // Mapping from user address to their encrypted counter value mapping(address => euint8) private counters; - constructor() { - TFHE.setFHEVM(FHEVMConfig.defaultConfig()); - } - function incrementBy(einput amount, bytes calldata inputProof) public { // Initialize counter if it doesn't exist if (!TFHE.isInitialized(counters[msg.sender])) { diff --git a/docs/fundamentals/first_step/start.md b/docs/fundamentals/first_step/start.md index ef8f555f..0d8d1ceb 100644 --- a/docs/fundamentals/first_step/start.md +++ b/docs/fundamentals/first_step/start.md @@ -19,6 +19,7 @@ Create a new file called `EncryptedCounter.sol` in your `contracts/` folder and pragma solidity ^0.8.24; import "fhevm/lib/TFHE.sol"; +import { MockZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; /// @title EncryptedCounter1 /// @notice A basic contract demonstrating the setup of encrypted types @@ -26,13 +27,11 @@ import "fhevm/lib/TFHE.sol"; /// @custom:experimental This is a minimal example contract intended only for learning purposes /// @custom:notice This contract has limited real-world utility and serves primarily as a starting point /// for understanding how to implement basic FHE operations in Solidity -contract EncryptedCounter1 { +contract EncryptedCounter1 is MockZamaFHEVMConfig { euint8 counter; euint8 CONST_ONE; constructor() { - TFHE.setFHEVM(FHEVMConfig.defaultConfig()); - // Initialize counter with an encrypted zero value counter = TFHE.asEuint8(0); TFHE.allowThis(counter); @@ -51,8 +50,28 @@ contract EncryptedCounter1 { ### How it works -1. **Configuring fhevm**: - The constructor initializes the FHEVM environment with a default configuration using `TFHE.setFHEVM(FHEVMConfig.defaultConfig())`. +1. **Configuring fhEVM**: + The contract inherits from `MockZamaFHEVMConfig` which provides the necessary configuration for local development and testing. This configuration includes the addresses of the TFHE library and Gateway contracts. + + When deploying to different networks, you can use the appropriate configuration: + + ```solidity + // For local testing + import { MockZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; + contract MyContract is MockZamaFHEVMConfig { ... } + + // For Sepolia testnet + import { SepoliaZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; + contract MyContract is SepoliaZamaFHEVMConfig { ... } + + // For Ethereum (when ready) + import { EthereumZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; + contract MyContract is EthereumZamaFHEVMConfig { ... } + ``` + + The configuration handles setting up: + - TFHE library address for encrypted operations + - Network-specific parameters 2. **Initializing encrypted variables**: @@ -138,12 +157,46 @@ The test file demonstrates key concepts for testing fhEVM smart contracts: - `contractFactory.deploy()`: Creates a new contract instance for testing - `tx.wait()`: Ensures transactions are mined before continuing -4. **Best Practices**: +## 🔧 Best Practices + +### General best practices - Deploy fresh contract instances for each test to ensure isolation - Use descriptive test names that explain the expected behavior - Handle asynchronous operations properly with async/await - Set up proper encryption instances for testing encrypted values +### No constant nor immutable encrypted state variables + +Never use encrypted types for constant or immutable state variables, even if they should actually stay constants, or else any transaction involving those will fail. This is because ciphertexts should always be stored in the privileged storage of the contract (see paragraph 4.4 of [whitepaper](../../fhevm-whitepaper.pdf)) while constant and immutable variables are just appended to the bytecode of the deployed contract at construction time. + +❌ So, even if `a` and `b` should never change after construction, the following example : + +```solidity +contract C { + euint32 internal constant a = TFHE.asEuint32(42); + euint32 internal immutable b; + + constructor(uint32 _b) { + b = TFHE.asEuint32(_b); + TFHE.allowThis(b); + } +} +``` + +✅ Should be replaced by this snippet: + +```solidity +contract C { + euint32 internal a = TFHE.asEuint32(42); + euint32 internal b; + + constructor(uint32 _b) { + b = TFHE.asEuint32(_b); + TFHE.allowThis(b); + } +} +``` + ## **Next Steps** Congratulations! You’ve configured and written your first confidential smart contract. Here are some ideas to expand your knowledge: diff --git a/docs/fundamentals/first_step/types.md b/docs/fundamentals/first_step/types.md index db4c3a1e..307564b8 100644 --- a/docs/fundamentals/first_step/types.md +++ b/docs/fundamentals/first_step/types.md @@ -82,7 +82,7 @@ The table below summarizes the available casting functions: When using encrypted types as state variables in smart contracts, avoid declaring them with the `immutable` or `constant` keywords. This is because the `TFHE.asEuintXX()` method relies on a precompiled contract, making the value resolution at compile time infeasible. -### Best practices for declaration +### 🔧 Best practices for declaration Instead of using `immutable` or `constant`, declare and initialize encrypted state variables like this: @@ -98,7 +98,6 @@ euint64 private totalSupply = TFHE.asEuint64(0); euint64 private totalSupply; constructor() { - TFHE.setFHEVM(FHEVMConfig.defaultConfig()); totalSupply = TFHE.asEuint64(0); } ``` diff --git a/docs/guides/contracts.md b/docs/guides/contracts.md new file mode 100644 index 00000000..70568c37 --- /dev/null +++ b/docs/guides/contracts.md @@ -0,0 +1,73 @@ +# Contracts standard library +This guide explains how to use the [fhEVM Contracts standard library](https://github.com/zama-ai/fhevm-contracts/tree/main). This library provides secure, extensible, and pre-tested Solidity templates designed for developing smart contracts on fhEVM using the TFHE library. + +## Overview +The **fhEVM Contracts Standard Library** streamlines the development of confidential smart contracts by providing templates and utilities for tokens, governance, and error management. These contracts have been rigorously tested by ZAMA's engineers and are designed to accelerate development while enhancing security. + +## Installation + +Install the library using your preferred package manager: + +```bash +# Using npm +npm install fhevm-contracts + +# Using Yarn +yarn add fhevm-contracts + +# Using pnpm +pnpm add fhevm-contracts +``` + +## Example + +### Local Testing with the Mock Network +When testing your contracts locally, you can use the `MockZamaFHEVMConfig` which provides a mock configuration for local development and testing. This allows you to test your contracts without needing to connect to a real network: + +```solidity +// SPDX-License-Identifier: BSD-3-Clause-Clear +pragma solidity ^0.8.24; + +import { MockZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; +import { EncryptedERC20 } from "fhevm-contracts/contracts/token/ERC20/EncryptedERC20.sol"; + +contract MyERC20 is MockZamaFHEVMConfig, EncryptedERC20 { + constructor() EncryptedERC20("MyToken", "MYTOKEN") { + _unsafeMint(1000000, msg.sender); + } +} +``` + +### Deploying to Ethereum Sepolia +When deploying to Sepolia, you can use the `SepoliaZamaFHEVMConfig` which provides the correct configuration for the Sepolia testnet: + +```solidity +// SPDX-License-Identifier: BSD-3-Clause-Clear +pragma solidity ^0.8.24; + +import { SepoliaZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; +import { EncryptedERC20 } from "fhevm-contracts/contracts/token/ERC20/EncryptedERC20.sol"; + +contract MyERC20 is SepoliaZamaFHEVMConfig, EncryptedERC20 { + constructor() EncryptedERC20("MyToken", "MYTOKEN") { + _unsafeMint(1000000, msg.sender); + } +} +``` +## 🔧 Best Practices for Contract Inheritance + +When inheriting from configuration contracts, the order of inheritance is critical. Since constructors are evaluated from left to right in Solidity, you must inherit the configuration contract first to ensure proper initialization. + +✅ **Correct Order**: +``` +contract MyERC20 is SepoliaZamaFHEVMConfig, EncryptedERC20 { ... } + ``` + +❌ **Wrong order**: +``` +contract MyERC20 is EncryptedERC20, SepoliaZamaFHEVMConfig { ... } +``` + +## Available contracts + +For a list of all available contracts see the page [See all tutorials](../tutorials/see-all-tutorials.md) \ No newline at end of file diff --git a/docs/guides/loop.md b/docs/guides/loop.md index 300d7c3f..4f8c281a 100644 --- a/docs/guides/loop.md +++ b/docs/guides/loop.md @@ -32,3 +32,69 @@ for (uint32 i = 0; i < 10; i++) { ``` In this snippet, we perform 10 iterations, adding 4 to `x` in each iteration as long as the iteration count is less than `maxValue`. If the iteration count exceeds `maxValue`, we add 0 instead for the remaining iterations because we can't break the loop. + + +## Best practises + +### Obfuscate branching + +The previous paragraph emphasized that branch logic should rely as much as possible on `TFHE.select` instead of decryptions. It hides effectively which branch has been executed. + +However, this is sometimes not enough. Enhancing the privacy of smart contracts often requires revisiting your application's logic. + +For example, if implementing a simple AMM for two encrypted ERC20 tokens based on a linear constant function, it is recommended to not only hide the amounts being swapped, but also the token which is swapped in a pair. + +✅ Here is a very simplified example implementations, we suppose here that the the rate between tokenA and tokenB is constant and equals to 1: + +```solidity +// typically either encryptedAmountAIn or encryptedAmountBIn is an encrypted null value +// ideally, the user already owns some amounts of both tokens and has pre-approved the AMM on both tokens +function swapTokensForTokens(einput encryptedAmountAIn, einput encryptedAmountBIn, bytes calldata inputProof) external { + euint32 encryptedAmountA = TFHE.asEuint32(encryptedAmountAIn, inputProof); // even if amount is null, do a transfer to obfuscate trade direction + euint32 encryptedAmountB = TFHE.asEuint32(encryptedAmountBIn, inputProof); // even if amount is null, do a transfer to obfuscate trade direction + + // send tokens from user to AMM contract + TFHE.allowTransient(encryptedAmountA, tokenA); + IEncryptedERC20(tokenA).transferFrom(msg.sender, address(this), encryptedAmountA); + + TFHE.allowTransient(encryptedAmountB, tokenB); + IEncryptedERC20(tokenB).transferFrom(msg.sender, address(this), encryptedAmountB); + + // send tokens from AMM contract to user + // Price of tokenA in tokenB is constant and equal to 1, so we just swap the encrypted amounts here + TFHE.allowTransient(encryptedAmountB, tokenA); + IEncryptedERC20(tokenA).transfer(msg.sender, encryptedAmountB); + + TFHE.allowTransient(encryptedAmountA, tokenB); + IEncryptedERC20(tokenB).transferFrom(msg.sender, address(this), encryptedAmountA); +} +``` + + +Notice that to preserve confidentiality, we had to make two inputs transfers on both tokens from the user to the AMM contract, and similarly two output transfers from the AMM to the user, even if technically most of the times it will make sense that one of the user inputs `encryptedAmountAIn` or `encryptedAmountBIn` is actually an encrypted zero. + +This is different from a classical non-confidential AMM with regular ERC20 tokens: in this case, the user would need to just do one input transfer to the AMM on the token being sold, and receive only one output transfer from the AMM on the token being bought. + +### Avoid using encrypted indexes + +Using encrypted indexes to pick an element from an array without revealing it is not very efficient, because you would still need to loop on all the indexes to preserve confidentiality. + +However, there are plans to make this kind of operation much more efficient in the future, by adding specialized operators for arrays. + +For instance, imagine you have an encrypted array called `encArray` and you want to update an encrypted value `x` to match an item from this list, `encArray[i]`, _without_ disclosing which item you're choosing. + +❌ You must loop over all the indexes and check equality homomorphically, however this pattern is very expensive in gas and should be avoided whenever possible. + +```solidity +euint32 x; +euint32[] encArray; + +function setXwithEncryptedIndex(einput encryptedIndex, bytes calldata inputProof) public { + euint32 index = TFHE.asEuint32(encryptedIndex, inputProof); + for (uint32 i = 0; i < encArray.length; i++) { + ebool isEqual = TFHE.eq(index, i); + x = TFHE.select(isEqual, encArray[i], x); + } + TFHE.allowThis(x); +} +``` diff --git a/docs/guides/pitfalls.md b/docs/guides/pitfalls.md deleted file mode 100644 index 2446cbcb..00000000 --- a/docs/guides/pitfalls.md +++ /dev/null @@ -1,156 +0,0 @@ -# Common pitfalls and best practises - -This document provides guidance on common pitfalls to avoid and best practices to follow when working with fhEVM. - -## Common pitfalls to avoid - -### No constant nor immutable encrypted state variables - -Never use encrypted types for constant or immutable state variables, even if they should actually stay constants, or else any transaction involving those will fail. This is because ciphertexts should always be stored in the privileged storage of the contract (see paragraph 4.4 of [whitepaper](../../fhevm-whitepaper.pdf)) while constant and immutable variables are just appended to the bytecode of the deployed contract at construction time. - -❌ So, even if `a` and `b` should never change after construction, the following example : - -```solidity -contract C { - euint32 internal constant a = TFHE.asEuint32(42); - euint32 internal immutable b; - - constructor(uint32 _b) { - b = TFHE.asEuint32(_b); - TFHE.allowThis(b); - } -} -``` - -✅ Should be replaced by this snippet: - -```solidity -contract C { - euint32 internal a = TFHE.asEuint32(42); - euint32 internal b; - - constructor(uint32 _b) { - b = TFHE.asEuint32(_b); - TFHE.allowThis(b); - } -} -``` - -## Best practises - -### Obfuscate branching - -The previous paragraph emphasized that branch logic should rely as much as possible on `TFHE.select` instead of decryptions. It hides effectively which branch has been executed. - -However, this is sometimes not enough. Enhancing the privacy of smart contracts often requires revisiting your application's logic. - -For example, if implementing a simple AMM for two encrypted ERC20 tokens based on a linear constant function, it is recommended to not only hide the amounts being swapped, but also the token which is swapped in a pair. - -✅ Here is a very simplified example implementations, we suppose here that the the rate between tokenA and tokenB is constant and equals to 1: - -```solidity -// typically either encryptedAmountAIn or encryptedAmountBIn is an encrypted null value -// ideally, the user already owns some amounts of both tokens and has pre-approved the AMM on both tokens -function swapTokensForTokens(einput encryptedAmountAIn, einput encryptedAmountBIn, bytes calldata inputProof) external { - euint32 encryptedAmountA = TFHE.asEuint32(encryptedAmountAIn, inputProof); // even if amount is null, do a transfer to obfuscate trade direction - euint32 encryptedAmountB = TFHE.asEuint32(encryptedAmountBIn, inputProof); // even if amount is null, do a transfer to obfuscate trade direction - - // send tokens from user to AMM contract - TFHE.allowTransient(encryptedAmountA, tokenA); - IEncryptedERC20(tokenA).transferFrom(msg.sender, address(this), encryptedAmountA); - - TFHE.allowTransient(encryptedAmountB, tokenB); - IEncryptedERC20(tokenB).transferFrom(msg.sender, address(this), encryptedAmountB); - - // send tokens from AMM contract to user - // Price of tokenA in tokenB is constant and equal to 1, so we just swap the encrypted amounts here - TFHE.allowTransient(encryptedAmountB, tokenA); - IEncryptedERC20(tokenA).transfer(msg.sender, encryptedAmountB); - - TFHE.allowTransient(encryptedAmountA, tokenB); - IEncryptedERC20(tokenB).transferFrom(msg.sender, address(this), encryptedAmountA); -} -``` - -Notice that to preserve confidentiality, we had to make two inputs transfers on both tokens from the user to the AMM contract, and similarly two output transfers from the AMM to the user, even if technically most of the times it will make sense that one of the user inputs `encryptedAmountAIn` or `encryptedAmountBIn` is actually an encrypted zero. - -This is different from a classical non-confidential AMM with regular ERC20 tokens: in this case, the user would need to just do one input transfer to the AMM on the token being sold, and receive only one output transfer from the AMM on the token being bought. - -### Avoid using encrypted indexes - -Using encrypted indexes to pick an element from an array without revealing it is not very efficient, because you would still need to loop on all the indexes to preserve confidentiality. - -However, there are plans to make this kind of operation much more efficient in the future, by adding specialized operators for arrays. - -For instance, imagine you have an encrypted array called `encArray` and you want to update an encrypted value `x` to match an item from this list, `encArray[i]`, _without_ disclosing which item you're choosing. - -❌ You must loop over all the indexes and check equality homomorphically, however this pattern is very expensive in gas and should be avoided whenever possible. - -```solidity -euint32 x; -euint32[] encArray; - -function setXwithEncryptedIndex(einput encryptedIndex, bytes calldata inputProof) public { - euint32 index = TFHE.asEuint32(encryptedIndex, inputProof); - for (uint32 i = 0; i < encArray.length; i++) { - ebool isEqual = TFHE.eq(index, i); - x = TFHE.select(isEqual, encArray[i], x); - } - TFHE.allowThis(x); -} -``` - -### Use scalar operands when possible to save gas - -Some TFHE operators exist in two versions : one where all operands are ciphertexts handles, and another where one of the operands is an unencrypted scalar. Whenever possible, use the scalar operand version, as this will save a lot of gas. See the page on [Gas](gas.md) to discover which operators support scalar operands and compare the gas saved between both versions: all-encrypted operands vs scalar. - -❌ For example, this snippet cost way more in gas: - -```solidity -euint32 x; -... -x = TFHE.add(x,TFHE.asEuint(42)); -``` - -✅ Than this one: - -```solidity -euint32 x; -... -x = TFHE.add(x,42); -``` - -Despite both leading to the same encrypted result! - -### Beware of overflows of TFHE arithmetic operators - -TFHE arithmetic operators can overflow. Do not forget to take into account such a possibility when implementing fhEVM smart contracts. - -❌ For example, if you wanted to create a mint function for an encrypted ERC20 tokens with an encrypted `totalSupply` state variable, this code is vulnerable to overflows: - -```solidity -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.allowThis(balances[msg.sender]); - TFHE.allow(balances[msg.sender], msg.sender); -} -``` - -✅ But you can fix this issue by using `TFHE.select` to cancel the mint in case of an overflow: - -```solidity -function mint(einput encryptedAmount, bytes calldata inputProof) public { - euint32 mintedAmount = TFHE.asEuint32(encryptedAmount, inputProof); - euint32 tempTotalSupply = TFHE.add(totalSupply, mintedAmount); - ebool isOverflow = TFHE.lt(tempTotalSupply, totalSupply); - 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.allowThis(balances[msg.sender]); - TFHE.allow(balances[msg.sender], msg.sender); -} -``` - -Notice that we did not check separately the overflow on `balances[msg.sender]` but only on `totalSupply` variable, because `totalSupply` is the sum of the balances of all the users, so `balances[msg.sender]` could never overflow if `totalSupply` did not. diff --git a/docs/tutorials/see-all-tutorials.md b/docs/tutorials/see-all-tutorials.md index f145c1ce..ddee3bb2 100644 --- a/docs/tutorials/see-all-tutorials.md +++ b/docs/tutorials/see-all-tutorials.md @@ -1,26 +1,41 @@ # See all tutorials -### Code examples in GitHub +## Code examples in GitHub -**Solidity smart contracts - templates** +### Solidity smart contracts - `fhevm-contracts` -- [ERC-20](https://github.com/zama-ai/fhevm-contracts/tree/main/contracts/token/ERC20): A variation of the standard ERC20 smart contract that incorporates encrypted balances, providing additional privacy for token holders. -- [Governance](https://github.com/zama-ai/fhevm-contracts/tree/main/contracts/governance): A DAO smart contract that facilitates governance decisions through encrypted voting +The [fhevm-contracts repository](https://github.com/zama-ai/fhevm-contracts) provides a comprehensive collection of secure, pre-tested Solidity templates optimized for fhEVM development. These templates leverage the TFHE library to enable encrypted computations while maintaining security and extensibility. -For more information on individual contracts, see the [fhevm-contracts repository](https://github.com/zama-ai/fhevm-contracts). +The library includes templates for common use cases like tokens and governance, allowing developers to quickly build confidential smart contracts with battle-tested components. For detailed implementation guidance and best practices, refer to the [contracts standard library guide](../guides/contracts.md). -**Solidity smart contract examples** +#### Token + +- [EncryptedERC20](https://github.com/zama-ai/fhevm-contracts/blob/main/contracts/token/ERC20/EncryptedERC20.sol): Standard ERC20 with encryption. +- [EncryptedERC20Mintable](https://github.com/zama-ai/fhevm-contracts/blob/main/contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol): ERC20 with minting capabilities. +- [EncryptedERC20WithErrors](https://github.com/zama-ai/fhevm-contracts/blob/main/contracts/token/ERC20/extensions/EncryptedERC20WithErrors.sol): ERC20 with integrated error handling. +- [EncryptedERC20WithErrorsMintable](https://github.com/zama-ai/fhevm-contracts/blob/main/contracts/token/ERC20/extensions/EncryptedERC20WithErrorsMintable.sol): ERC20 with both minting and error handling. + +#### Governance + +- [Comp](https://github.com/zama-ai/fhevm-contracts/blob/main/contracts/governance/Comp.sol): Governance token implementation. +- [GovernorAlphaZama](https://github.com/zama-ai/fhevm-contracts/blob/main/contracts/governance/GovernorAlphaZama.sol): A governance contract for managing proposals and votes. + +#### Utils + +- [EncryptedErrors](https://github.com/zama-ai/fhevm-contracts/blob/main/contracts/utils/EncryptedErrors.sol): Provides error management utilities for encrypted contracts. + +### Other Solidity smart contract examples - [Blind Auction](https://github.com/zama-ai/fhevm/blob/main/examples/BlindAuction.sol): A smart contract for conducting blind auctions where bids are encrypted and the winning bid remains private. - [Decentralized ID](https://github.com/poppyseedDev/FHEPass): A blockchain-based identity management system using smart contracts to store and manage encrypted personal data. - [Cipherbomb](https://github.com/immortal-tofu/cipherbomb): A multiplayer game where players must defuse an encrypted bomb by guessing the correct sequence of numbers. - [Voting example](https://github.com/allemanfredi/suffragium): Suffragium is a secure, privacy-preserving voting system that combines zero-knowledge proofs (ZKP) and Fully Homomorphic Encryption (FHE) to create a trustless and tamper-resistant voting platform. -**Frontend examples** +### Frontend examples - [Cipherbomb UI](https://github.com/immortal-tofu/cipherbomb-ui): A multiplayer game where players must defuse an encrypted bomb by guessing the correct sequence of numbers. -### Blog tutorials: +## Blog tutorials: - [Suffragium: An Encrypted Onchain Voting System Leveraging ZK and FHE Using Zama's fhEVM](https://www.zama.ai/post/encrypted-onchain-voting-using-zk-and-fhe-with-zama-fhevm) @@ -32,9 +47,10 @@ For more information on individual contracts, see the [fhevm-contracts repositor - [On-chain Blind Auctions Using Homomorphic Encryption and the fhEVM](https://www.zama.ai/post/on-chain-blind-auctions-using-homomorphic-encryption) - July 2023 - [Confidential ERC-20 Tokens Using Homomorphic Encryption and the fhEVM](https://www.zama.ai/post/confidential-erc-20-tokens-using-homomorphic-encryption) - June 2023 -### Video tutorials: +## Video tutorials: -- [Zama - FHE on Ethereum (Presentation at The Zama CoFHE Shop during EthCC 7)](https://www.youtube.com/watch?v=WngC5cvV_fc&ab_channel=Zama) +- [How to do Confidential Transactions Directly on Ethereum?](https://www.youtube.com/watch?v=aDv2WYOpVqA) - Nov 2024 +- [Zama - FHE on Ethereum (Presentation at The Zama CoFHE Shop during EthCC 7)](https://www.youtube.com/watch?v=WngC5cvV_fc&ab_channel=Zama) - Jul 2024 #### Legacy - Not compatible with latest fhEVM