From ad6bfacd7c1f955a1619922d81eff7867d53dbae Mon Sep 17 00:00:00 2001 From: Aurora Poppyseed <30662672+poppyseedDev@users.noreply.github.com> Date: Thu, 12 Dec 2024 07:25:03 +0900 Subject: [PATCH] docs: fix due to change in hardhat-templates README trivial encrypt casting (#642) * docs: update README and MockZamaFHEVMConfig removed * docs: update typescript sample templates * docs: gas added * docs: resolve webpack error structure * docs: readme upgrade and tests * docs: mini change * docs: review * docs: added immutable * docs: types removed Declaring encrypted state variables * docs: add asxxoperation * docs: added asXXoperation * docs: mini change * docs: apply suggestions from code review Co-authored-by: yuxizama <157474013+yuxizama@users.noreply.github.com> * docs: mini changes * docs: mini changes * docs: mini change * docs: mini change Co-authored-by: yuxizama <157474013+yuxizama@users.noreply.github.com> * Update README.md Co-authored-by: Aurora Poppyseed <30662672+poppyseedDev@users.noreply.github.com> * Update README.md Co-authored-by: Aurora Poppyseed <30662672+poppyseedDev@users.noreply.github.com> * Update README.md Co-authored-by: Aurora Poppyseed <30662672+poppyseedDev@users.noreply.github.com> * Update README.md Co-authored-by: Aurora Poppyseed <30662672+poppyseedDev@users.noreply.github.com> * Update docs/fundamentals/asXXoperation.md Co-authored-by: Aurora Poppyseed <30662672+poppyseedDev@users.noreply.github.com> * Update docs/fundamentals/asXXoperation.md Co-authored-by: Aurora Poppyseed <30662672+poppyseedDev@users.noreply.github.com> * Update docs/fundamentals/asXXoperation.md Co-authored-by: Aurora Poppyseed <30662672+poppyseedDev@users.noreply.github.com> * Update docs/fundamentals/asXXoperation.md Co-authored-by: Aurora Poppyseed <30662672+poppyseedDev@users.noreply.github.com> * Update docs/fundamentals/asXXoperation.md Co-authored-by: Aurora Poppyseed <30662672+poppyseedDev@users.noreply.github.com> * docs: mini changes * docs: gitbook problems * docs: mini change * docs: change * docs: remove changes from tests * docs: mini update --------- Co-authored-by: yuxizama <157474013+yuxizama@users.noreply.github.com> Co-authored-by: jat <153528475+jatZama@users.noreply.github.com> --- README.md | 125 ++++++------ docs/SUMMARY.md | 3 + docs/fundamentals/acl/acl_examples.md | 6 +- docs/fundamentals/asEXXoperators.md | 159 +++++++++++++++ docs/fundamentals/configure.md | 26 +-- docs/fundamentals/decryption/decrypt.md | 32 +-- .../decryption/decrypt_details.md | 6 +- docs/fundamentals/decryption/reencryption.md | 82 ++++---- docs/fundamentals/inputs.md | 21 +- docs/fundamentals/types.md | 68 ------- docs/getting_started/ethereum.md | 2 +- docs/getting_started/first_smart_contract.md | 26 +-- docs/guides/contracts.md | 20 +- docs/guides/debug_decrypt.md | 117 +++++++++++ docs/guides/error_handling.md | 2 +- docs/guides/frontend/webpack.md | 26 ++- docs/guides/gas.md | 184 +++++++++++++++--- docs/guides/loop.md | 8 +- package-lock.json | 9 +- package.json | 2 +- 20 files changed, 614 insertions(+), 310 deletions(-) create mode 100644 docs/fundamentals/asEXXoperators.md create mode 100644 docs/guides/debug_decrypt.md diff --git a/README.md b/README.md index 57e8dd70..af6c177f 100644 --- a/README.md +++ b/README.md @@ -88,8 +88,6 @@ _Learn more use cases in the [list of examples](https://docs.zama.ai/fhevm/tutor ### Installation -For now, fhEVM is implemented on evmos. - ```bash # Using npm npm install fhevm @@ -101,9 +99,6 @@ yarn add fhevm pnpm add fhevm ``` -_Find more details on implementation instructions in [this repository](https://github.com/zama-ai/fhevm-evmos)._ -

- ### A Simple Example ```solidity @@ -112,19 +107,25 @@ _Find more details on implementation instructions in [this repository](https://g pragma solidity ^0.8.24; import "fhevm/lib/TFHE.sol"; +import "fhevm/config/ZamaFHEVMConfig.sol"; -contract Counter { - euint32 counter; +contract Counter is SepoliaZamaFHEVMConfig { + euint8 internal counter; + + constructor() { + counter = TFHE.asEuint8(0); + TFHE.allowThis(counter); + } function add(einput valueInput, bytes calldata inputProof) public { - euint32 value = TFHE.asEuint32(valueInput, inputProof); + euint8 value = TFHE.asEuint8(valueInput, inputProof); counter = TFHE.add(counter, value); - TFHE.allow(counter, address(this)); + TFHE.allowThis(counter); } } ``` -_More examples are available [here](https://github.com/zama-ai/fhevm/tree/main/examples)._ +_More examples are available [here](https://docs.zama.ai/fhevm/tutorials/see-all-tutorials)._

↑ Back to top @@ -136,27 +137,61 @@ _More examples are available [here](https://github.com/zama-ai/fhevm/tree/main/e ## Resources -### White paper +### **White Paper** -- [Confidential EVM Smart Contracts using Fully Homomorphic Encryption](https://github.com/zama-ai/fhevm/blob/main/fhevm-whitepaper-v2.pdf) -

+Gain insights into the technology powering fhEVM with our in-depth white paper: +πŸ‘‰ [**Confidential EVM Smart Contracts using Fully Homomorphic Encryption**](https://github.com/zama-ai/fhevm/blob/main/fhevm-whitepaper-v2.pdf) + +--- + +### **Demos and Tutorials** + +Access a curated collection of demos and step-by-step tutorials to guide your development journey: +πŸ”— [**Visit the Tutorials Page**](https://docs.zama.ai/fhevm/tutorials/see-all-tutorials) + +--- + +### **Documentation** + +Master `fhEVM` and build smart contracts using these resources: -### Demos and Tutorials +- πŸ“˜ [**Comprehensive fhEVM Documentation**](https://docs.zama.ai/fhevm) + Dive deep into Zama's detailed guide for utilizing the full potential of fhEVM. -For a comprehensive list of demos and tutorials, visit our [tutorials page](https://docs.zama.ai/fhevm/tutorials/see-all-tutorials). +- πŸ€– [**ZAMA Solidity Developer (Modified ChatGPT Model)**](https://chatgpt.com/g/g-67518aee3c708191b9f08d077a7d6fa1-zama-solidity-developer) + Accelerate your smart contract development with AI-powered assistance. -### Documentation +### **Development templates** -Full, comprehensive documentation is available here: [https://docs.zama.ai/fhevm](https://docs.zama.ai/fhevm). +Start building faster with pre-configured templates tailored for various frameworks: + +#### **Smart Contracts** + +- πŸ”§ [**Hardhat Template**](https://github.com/zama-ai/fhevm-hardhat-template) + Smart contracts testing and development <- **_primary entry point for developers wanting to develop smart contracts on fhEVM_** +- πŸ’» [**fhEVM Contracts**](https://github.com/zama-ai/fhevm-contracts) + Library of standardized fhEVM contracts. + +#### **Frontend frameworks** + +- 🌐 [**React.js Template**](https://github.com/zama-ai/fhevm-react-template) + Simplify your FHE dApp development with a clean and optimized React.js template. +- ⚑ [**Next.js Template**](https://github.com/zama-ai/fhevm-next-template) + Build server-rendered, scalable dApps with FHE support using this Next.js template. +- πŸ–ΌοΈ [**Vue.js Template**](https://github.com/zama-ai/fhevm-vue-template) + Create modular, responsive dApps with FHE capabilities using Vue.js. + +--- + +### πŸš€ **Kickstart Your Project Today!** + +Leverage these templates to accelerate your development process and bring your ideas to life faster.

↑ Back to top

-### Blockchain Implementation - -To support fhEVM in an EVM-based blockchain, the **fhevm-go** library can be used as it implements all the needed FHE functionalities. -It is available here: [fhevm-go](https://github.com/zama-ai/fhevm-go) +## Blockchain Implementation To integrate fhevm-go into any EVM-based blockchain, you can follow the [Integration Guide](https://docs.zama.ai/fhevm-go/getting_started/integration). @@ -187,8 +222,6 @@ Files that are generated now (can be seen inside `codegen/main.ts`) ``` lib/Impl.sol lib/TFHE.sol -mocks/Impl.sol -mocks/TFHE.sol contracts/tests/TFHETestSuiteX.sol test/tfheOperations/tfheOperations.ts ``` @@ -197,57 +230,11 @@ test/tfheOperations/tfheOperations.ts ↑ Back to top

-#### Tests - -The easiest way to understand how to write/dev smart contract and interact with them using **fhevmjs** is to read and explore the available tests in this repository. - -##### Fast start - -```bash -# in one terminal -npm run fhevm:start -# in another terminal -npm i -cp .env.example .env -npm run test:mock -``` - - - -##### Run test on a real fhEVM - -```bash -npm run test -- --network sepolia -``` - #### Adding new operators Operators can be defined as data inside `codegen/common.ts` file and code automatically generates solidity overloads. Test for overloads must be added (or the build doesn't pass) inside `codegen/overloadsTests.ts` file. -#### Mocked mode - -The mocked mode allows faster testing and the ability to analyze coverage of the tests. In this mocked version, encrypted types are not really encrypted, and the tests are run on the original version of the EVM, on a local hardhat network instance. To run the tests in mocked mode, you can use directly the following command: - -```bash -npm run test:mock -``` - -To analyze the coverage of the tests (in mocked mode necessarily, as this cannot be done on the real fhEVM node), you can use this command : - -```bash -npm run coverage:mock -``` - -Then open the file `coverage/index.html`. You can see there which line or branch for each contract which has been covered or missed by your test suite. This allows increased security by pointing out missing branches not covered yet by the current tests. - -> [!Note] -> Due to intrinsic limitations of the original EVM, the mocked version differ in few corner cases from the real fhEVM, the main difference is the difference in gas prices for the FHE operations. This means that before deploying to production, developers still need to run the tests with the original fhEVM node, as a final check in non-mocked mode, with `npm run test`. - -

- ↑ Back to top -

- ### Citations To cite fhEVM or the whitepaper in academic papers, please use the following entries: diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 21b3e06b..03b692da 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -22,6 +22,7 @@ - [Configuration](fundamentals/configure.md) - [Supported types](fundamentals/types.md) - [Operations on encrypted types](fundamentals/operations.md) +- [asEbool, asEuintXX, asEaddress and asEbytesXX operations](fundamentals/asEXXoperators.md) - [Access Control List](fundamentals/acl/README.md) - [ACL examples](fundamentals/acl/acl_examples.md) - [Encrypted Inputs](fundamentals/inputs.md) @@ -38,6 +39,8 @@ - [Branching in FHE](guides/conditions.md) - [Generate random numbers](guides/random.md) - [Error handling](guides/error_handling.md) + - [Gas estimation](guides/gas.md) + - [Debug decrypt](guides/debug_decrypt.md) - [Frontend](guides/frontend/README.md) - [Build a web application](guides/frontend/webapp.md) - [Build with Node](guides/frontend/node.md) diff --git a/docs/fundamentals/acl/acl_examples.md b/docs/fundamentals/acl/acl_examples.md index 94ce5bab..ecb63af3 100644 --- a/docs/fundamentals/acl/acl_examples.md +++ b/docs/fundamentals/acl/acl_examples.md @@ -33,9 +33,9 @@ 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"; +import { SepoliaZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; -contract SecretGiver is MockZamaFHEVMConfig { +contract SecretGiver is SepoliaZamaFHEVMConfig { SecretStore public secretStore; constructor() { @@ -56,7 +56,7 @@ contract SecretGiver is MockZamaFHEVMConfig { ``` ``` -contract SecretStore is MockZamaFHEVMConfig { +contract SecretStore is SepoliaZamaFHEVMConfig { euint16 public secretResult; function storeSecret(euint16 callerSecret) public { diff --git a/docs/fundamentals/asEXXoperators.md b/docs/fundamentals/asEXXoperators.md new file mode 100644 index 00000000..a8b98e6b --- /dev/null +++ b/docs/fundamentals/asEXXoperators.md @@ -0,0 +1,159 @@ +# asEbool, asEuintXX, asEaddress and asEbytesXX operations + +This documentation covers the `asEbool`, `asEuintXX`, `asEaddress` and `asEbytesXX` operations provided by the TFHE library for working with encrypted data in the fhEVM. These operations are essential for converting between plaintext and encrypted types, as well as handling encrypted inputs. + +The operations can be categorized into three main use cases: + +1. **Trivial encryption**: Converting plaintext values to encrypted types +2. **Type casting**: Converting between different encrypted types +3. **Input handling**: Processing encrypted inputs with proofs + +## 1. Trivial encryption + +Trivial encryption simply put is a plain text in a format of a ciphertext. + +### Overview + +Trivial encryption is the process of converting plaintext values into encrypted types (ciphertexts) compatible with TFHE operators. Although the data is in ciphertext format, it remains publicly visible on-chain, making it useful for operations between public and private values. + +This type of casting involves converting plaintext (unencrypted) values into their encrypted equivalents, such as: + +- `bool` β†’ `ebool` +- `uint` β†’ `euintXX` +- `bytes` β†’ `ebytesXX` +- `address` β†’ `eaddress` + +> **Note**: When doing trivial encryption, the data is made compatible with FHE operations but remains publicly visible on-chain unless explicitly encrypted. + +#### **Example** + +```solidity +euint64 value64 = TFHE.asEuint64(7262); // Trivial encrypt a uint64 +ebool valueBool = TFHE.asEbool(true); // Trivial encrypt a boolean +``` + +### Trivial encryption of `ebytesXX` types + +The `TFHE.padToBytesXX` functions facilitate this trivial encryption process for byte arrays, ensuring compatibility with `ebytesXX` types. These functions: + +- Pad the provided byte array to the appropriate length (`64`, `128`, or `256` bytes). +- Prevent runtime errors caused by improperly sized input data. +- Work seamlessly with `TFHE.asEbytesXX` for trivial encryption. + +> **Important**: Trivial encryption does NOT provide any privacy guarantees. The input data remains fully visible on the blockchain. Only use trivial encryption when working with public values that need to interact with actual encrypted data. + +#### Workflow + +1. **Pad Input Data**: + Use the `padToBytesXX` functions to ensure your byte array matches the size requirements. +2. **Encrypt the Padded Data**: + Use `TFHE.asEbytesXX` to encrypt the padded byte array into the corresponding encrypted type. +3. **Grant Access**: + Use `TFHE.allowThis` and `TFHE.allow`optionally, if you want to persist allowance for those variables for later use. + +### Example: Trivial Encryption with `ebytesXX` + +Below is an example demonstrating how to encrypt and manage `ebytes64`, `ebytes128`, and `ebytes256` types: + +```solidity +function trivialEncrypt() public { + // Encrypt a 64-byte array + ebytes64 yBytes64 = TFHE.asEbytes64( + TFHE.padToBytes64( + hex"19d179e0cc7e816dc944582ed4f5652f5951900098fc2e0a15a7ea4dc8cfa4e3b6c54beea5ee95e56b728762f659347ce1d4aa1b05fcc5" + ) + ); + TFHE.allowThis(yBytes64); + TFHE.allow(yBytes64, msg.sender); + + // Encrypt a 128-byte array + ebytes128 yBytes128 = TFHE.asEbytes128( + TFHE.padToBytes128( + hex"13e7819123de6e2870c7e83bb764508e22d7c3ab8a5aee6bdfb26355ef0d3f1977d651b83bf5f78634fa360aa14debdc3daa6a587b5c2fb1710ab4d6677e62a8577f2d9fecc190ad8b11c9f0a5ec3138b27da1f055437af8c90a9495dad230" + ) + ); + TFHE.allowThis(yBytes128); + TFHE.allow(yBytes128, msg.sender); + + // Encrypt a 256-byte array + ebytes256 yBytes256 = TFHE.asEbytes256( + TFHE.padToBytes256( + hex"d179e0cc7e816dc944582ed4f5652f5951900098fc2e0a15a7ea4dc8cfa4e3b6c54beea5ee95e56b728762f659347ce1d4aa1b05fcc513e7819123de6e2870c7e83bb764508e22d7c3ab8a5aee6bdfb26355ef0d3f1977d651b83bf5f78634fa360aa14debdc3daa6a587b5c2fb1710ab4d6677e62a8577f2d9fecc190ad8b11c9f0a5ec3138b27da1f055437af8c90a9495dad230" + ) + ); + TFHE.allowThis(yBytes256); + TFHE.allow(yBytes256, msg.sender); +} +``` + +## 2. Casting between encrypted types + +This type of casting is used to reinterpret or convert one encrypted type into another. For example: + +- `euint32` β†’ `euint64` +- `ebytes128` β†’ `ebytes256` + +Casting between encrypted types is often required when working with operations that demand specific sizes or precisions. + +> **Important**: When casting between encrypted types: +> +> - Casting from smaller types to larger types (e.g. `euint32` β†’ `euint64`) preserves all information +> - Casting from larger types to smaller types (e.g. `euint64` β†’ `euint32`) will truncate and lose information + +The table below summarizes the available casting functions: + +| From type | To type | Function | +| --------- | -------- | ---------------- | +| `euintX` | `euintX` | `TFHE.asEuintXX` | +| `ebool` | `euintX` | `TFHE.asEuintXX` | +| `euintX` | `ebool` | `TFHE.asEboolXX` | + +{% hint style="info" %} +Casting between encrypted types is efficient and often necessary when handling data with differing precision requirements. +{% endhint %} + +### **Workflow for encrypted types** + +```solidity +// Casting between encrypted types +euint32 value32 = TFHE.asEuint32(value64); // Cast to euint32 +ebool valueBool = TFHE.asEbool(value32); // Cast to ebool +``` + +## 3. Encrypted input + +### Overview + +Encrypted input casting is the process of interpreting a handle (ciphertext reference) and its proof as a specific encrypted type. This ensures the validity of the input before it is used in computations. + +Encrypted inputs is in depth explained in the following section: [encrypted inputs](./inputs.md) + +#### Example + +```solidity +euint64 encryptedValue = TFHE.asEuint64(einputHandle, inputProof); // Interpret einputHandle as euint64 +``` + +#### Details + +Encrypted input casting validates: + +1. The input handle references a valid ciphertext. +2. The accompanying proof matches the expected type. + +For more information, see the [Encrypetd inputs documentation](./inputs.md) + +## Overall operation summary + +| Casting Type | Function | Input Type | Output Type | +| ------------------------ | ----------------------- | ----------------------- | ----------- | +| Trivial encryption | `TFHE.asEuintXX(x)` | `uintX` | `euintX` | +| | `TFHE.asEbool(x)` | `bool` | `ebool` | +| | `TFHE.asEbytesXX(x)` | `bytesXX` | `ebytesXX` | +| | `TFHE.asEaddress(x)` | `address` | `eaddress` | +| Conversion between types | `TFHE.asEuintXX(x)` | `euintXX`/`ebool` | `euintYY` | +| | `TFHE.asEbool(x)` | `euintXX` | `ebool` | +| Encrypted input | `TFHE.asEuintXX(x, y)` | `einput`, `bytes` proof | `euintX` | +| | `TFHE.asEbool(x, y)` | `einput`,`bytes` proof | `ebool` | +| | `TFHE.asEbytesXX(x, y)` | `einput`,`bytes` proof | `ebytesXX` | +| | `TFHE.asEaddress(x, y)` | `einput`, `bytes` proof | `eaddress` | diff --git a/docs/fundamentals/configure.md b/docs/fundamentals/configure.md index 58209bbc..3130f6d3 100644 --- a/docs/fundamentals/configure.md +++ b/docs/fundamentals/configure.md @@ -21,14 +21,8 @@ This configuration contract initializes the **fhEVM environment** with required **Import based on your environment:** ```solidity -// For Mock testnet -import { MockZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; - // For Ethereum Sepolia import { SepoliaZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; - -// For Ethereum Mainnet (when ready) -import { EthereumZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; ``` **Purpose:** @@ -36,15 +30,15 @@ import { EthereumZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; - Sets encryption parameters such as cryptographic keys and supported ciphertext types. - Ensures proper initialization of the FHEVM environment. -**Example: using mock configuration** +**Example: using Sepolia configuration** ```solidity // SPDX-License-Identifier: BSD-3-Clause-Clear pragma solidity ^0.8.24; -import { MockZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; +import { SepoliaZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; -contract MyERC20 is MockZamaFHEVMConfig { +contract MyERC20 is SepoliaZamaFHEVMConfig { constructor() { // Additional initialization logic if needed } @@ -58,14 +52,8 @@ To perform decryption or reencryption, your contract must interact with the **Ga **Import based on your environment** ```solidity -// For Mock testnet -import { MockZamaGatewayConfig } from "fhevm/config/ZamaGatewayConfig.sol"; - // For Ethereum Sepolia import { SepoliaZamaGatewayConfig } from "fhevm/config/ZamaGatewayConfig.sol"; - -// For Ethereum Mainnet (when ready) -import { EthereumZamaGatewayConfig } from "fhevm/config/ZamaGatewayConfig.sol"; ``` **Purpose** @@ -73,15 +61,15 @@ import { EthereumZamaGatewayConfig } from "fhevm/config/ZamaGatewayConfig.sol"; - Configures the Gateway for secure cryptographic operations. - Facilitates reencryption and decryption requests. -**Example: Configuring the gateway with mock settings** +**Example: Configuring the gateway with Sepolia settings** ```solidity import "fhevm/lib/TFHE.sol"; -import { MockZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; -import { MockZamaGatewayConfig } from "fhevm/config/ZamaGatewayConfig.sol"; +import { SepoliaZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; +import { SepoliaZamaGatewayConfig } from "fhevm/config/ZamaGatewayConfig.sol"; import "fhevm/gateway/GatewayCaller.sol"; -contract Test is MockZamaFHEVMConfig, MockZamaGatewayConfig, GatewayCaller { +contract Test is SepoliaZamaFHEVMConfig, SepoliaZamaGatewayConfig, GatewayCaller { constructor() { // Gateway and FHEVM environment initialized automatically } diff --git a/docs/fundamentals/decryption/decrypt.md b/docs/fundamentals/decryption/decrypt.md index 066ef25a..a64764f5 100644 --- a/docs/fundamentals/decryption/decrypt.md +++ b/docs/fundamentals/decryption/decrypt.md @@ -25,11 +25,11 @@ 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 { SepoliaZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; +import { SepoliaZamaGatewayConfig } from "fhevm/config/ZamaGatewayConfig.sol"; import "fhevm/gateway/GatewayCaller.sol"; -contract TestAsyncDecrypt is MockZamaFHEVMConfig, MockZamaGatewayConfig, GatewayCaller { +contract TestAsyncDecrypt is SepoliaZamaFHEVMConfig, SepoliaZamaGatewayConfig, GatewayCaller { ebool xBool; bool public yBool; @@ -55,8 +55,8 @@ contract TestAsyncDecrypt is MockZamaFHEVMConfig, MockZamaGatewayConfig, Gateway 1. **Configuration imports**: The configuration contracts are imported to set up the FHEVM environment and Gateway. ```solidity - import { MockZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; - import { MockZamaGatewayConfig } from "fhevm/config/ZamaGatewayConfig.sol"; + import { SepoliaZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; + import { SepoliaZamaGatewayConfig } from "fhevm/config/ZamaGatewayConfig.sol"; ``` 2. **`GatewayCaller` import**:\ @@ -75,17 +75,17 @@ Remember our [**Encrypted Counter**](../../getting_started/first_smart_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 { SepoliaZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; +import { SepoliaZamaGatewayConfig } 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 MockZamaFHEVMConfig, MockZamaGatewayConfig, GatewayCaller { +contract EncryptedCounter3 is SepoliaZamaFHEVMConfig, SepoliaZamaGatewayConfig, GatewayCaller { /// @dev Decrypted state variable - euint8 counter; + euint8 internal counter; uint8 public decryptedCounter; constructor() { @@ -133,14 +133,14 @@ Here’s a sample test for the Encrypted Counter contract using Hardhat: ```ts import { awaitAllDecryptionResults, initGateway } from "../asyncDecrypt"; -import { createInstances } from "../instance"; +import { createInstance } from "../instance"; import { getSigners, initSigners } from "../signers"; import { expect } from "chai"; import { ethers } from "hardhat"; describe("EncryptedCounter3", function () { before(async function () { - await initSigners(2); // Initialize signers + await initSigners(); // Initialize signers this.signers = await getSigners(); await initGateway(); // Initialize the gateway for decryption }); @@ -150,12 +150,12 @@ describe("EncryptedCounter3", function () { this.counterContract = await CounterFactory.connect(this.signers.alice).deploy(); await this.counterContract.waitForDeployment(); this.contractAddress = await this.counterContract.getAddress(); - this.instances = await createInstances(this.signers); // Set up instances for testing + this.instances = await createInstance(); // Set up instances for testing }); - it("should increment counter multiple times and decrypt the result", async function () { + it("should increment counter and decrypt the result", async function () { // Create encrypted input for amount to increment by - const input = this.instances.alice.createEncryptedInput(this.contractAddress, this.signers.alice.address); + const input = this.instances.createEncryptedInput(this.contractAddress, this.signers.alice.address); input.add8(5); // Increment by 5 as an example const encryptedAmount = await input.encrypt(); @@ -163,13 +163,13 @@ describe("EncryptedCounter3", function () { const tx = await this.counterContract.incrementBy(encryptedAmount.handles[0], encryptedAmount.inputProof); await tx.wait(); - const tx4 = await this.counterContract.connect(this.signers.carol).requestDecryptCounter({ gasLimit: 5_000_000 }); + const tx4 = await this.counterContract.connect(this.signers.carol).requestDecryptCounter(); await tx4.wait(); // Wait for decryption to complete await awaitAllDecryptionResults(); - // Check decrypted value + // Check decrypted value (should be 3: initial 0 + three increments) const decryptedValue = await this.counterContract.getDecryptedCounter(); expect(decryptedValue).to.equal(5); }); diff --git a/docs/fundamentals/decryption/decrypt_details.md b/docs/fundamentals/decryption/decrypt_details.md index b057ef53..0b0b10da 100644 --- a/docs/fundamentals/decryption/decrypt_details.md +++ b/docs/fundamentals/decryption/decrypt_details.md @@ -114,11 +114,11 @@ 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 { SepoliaZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; +import { SepoliaZamaGatewayConfig } from "fhevm/config/ZamaGatewayConfig.sol"; import "fhevm/gateway/GatewayCaller.sol"; -contract TestAsyncDecrypt is MockZamaFHEVMConfig, MockZamaGatewayConfig, GatewayCaller { +contract TestAsyncDecrypt is SepoliaZamaFHEVMConfig, SepoliaZamaGatewayConfig, GatewayCaller { euint32 xUint32; uint32 public yUint32; diff --git a/docs/fundamentals/decryption/reencryption.md b/docs/fundamentals/decryption/reencryption.md index acd681e9..b5f340cf 100644 --- a/docs/fundamentals/decryption/reencryption.md +++ b/docs/fundamentals/decryption/reencryption.md @@ -30,7 +30,7 @@ To retrieve the ciphertext that needs to be re-encrypted, you can implement a vi ```solidity import "fhevm/lib/TFHE.sol"; -contract EncryptedERC20 { +contract ConfidentialERC20 { ... function balanceOf(account address) public view returns (bytes euint64) { return balances[msg.sender]; @@ -58,7 +58,7 @@ const provider = new BrowserProvider(window.ethereum); const accounts = await provider.send("eth_requestAccounts", []); const USER_ADDRESS = accounts[0]; -await initSigners(2); // Initialize signers +await initSigners(); // Initialize signers const signers = await getSigners(); const instance = await createInstances(this.signers); @@ -73,8 +73,8 @@ const params = [USER_ADDRESS, JSON.stringify(eip712)]; const signature = await window.ethereum.request({ method: "eth_signTypedData_v4", params }); // Get the ciphertext to reencrypt -const encryptedERC20 = new Contract(CONTRACT_ADDRESS, abi, signer).connect(provider); -const encryptedBalance = encryptedERC20.balanceOf(userAddress); +const ConfidentialERC20 = new Contract(CONTRACT_ADDRESS, abi, signer).connect(provider); +const encryptedBalance = ConfidentialERC20.balanceOf(userAddress); // This function will call the gateway and decrypt the received value with the provided private key const userBalance = instance.reencrypt( @@ -108,14 +108,14 @@ 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"; +import { SepoliaZamaFHEVMConfig } 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 is MockZamaFHEVMConfig { +contract EncryptedCounter4 is SepoliaZamaFHEVMConfig { // Mapping from user address to their encrypted counter value mapping(address => euint8) private counters; @@ -144,35 +144,15 @@ contract EncryptedCounter4 is MockZamaFHEVMConfig { Here’s a sample test to verify re-encryption functionality: ```ts -import { expect } from "chai"; -import { ethers } from "hardhat"; - -import { initGateway, awaitAllReEncryptionResults } from "../asyncReEncrypt"; -import { createInstances } from "../instance"; +import { createInstance } from "../instance"; +import { reencryptEuint8 } from "../reencrypt"; import { getSigners, initSigners } from "../signers"; - -import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers"; import { expect } from "chai"; -import type { FhevmInstance } from "fhevmjs"; import { ethers } from "hardhat"; -import { createInstances } from "../instance"; -import { getSigners, initSigners } from "../signers"; - -/** - * Helper function to setup reencryption - */ -async function setupReencryption(instance: FhevmInstance, signer: HardhatEthersSigner, contractAddress: string) { - const { publicKey, privateKey } = instance.generateKeypair(); - const eip712 = instance.createEIP712(publicKey, contractAddress); - const signature = await signer.signTypedData(eip712.domain, { Reencrypt: eip712.types.Reencrypt }, eip712.message); - - return { publicKey, privateKey, signature: signature.replace("0x", "") }; -} - describe("EncryptedCounter4", function () { before(async function () { - await initSigners(2); // Initialize signers + await initSigners(); // Initialize signers this.signers = await getSigners(); }); @@ -181,11 +161,11 @@ describe("EncryptedCounter4", function () { this.counterContract = await CounterFactory.connect(this.signers.alice).deploy(); await this.counterContract.waitForDeployment(); this.contractAddress = await this.counterContract.getAddress(); - this.instances = await createInstances(this.signers); // Set up instances for testing + this.instances = await createInstance(); }); it("should allow reencryption and decryption of counter value", async function () { - const input = this.instances.alice.createEncryptedInput(this.contractAddress, this.signers.alice.address); + const input = this.instances.createEncryptedInput(this.contractAddress, this.signers.alice.address); input.add8(1); // Increment by 1 as an example const encryptedAmount = await input.encrypt(); @@ -196,28 +176,44 @@ describe("EncryptedCounter4", function () { // Get the encrypted counter value const encryptedCounter = await this.counterContract.getCounter(); - // Set up reencryption keys and signature - const { publicKey, privateKey, signature } = await setupReencryption( - this.instances.alice, - this.signers.alice, + const decryptedValue = await reencryptEuint8( + this.signers, + this.instances, + "alice", + encryptedCounter, this.contractAddress, ); - // Perform reencryption and decryption - const decryptedValue = await this.instances.alice.reencrypt( + // Verify the decrypted value is 1 (since we incremented once) + expect(decryptedValue).to.equal(1); + }); + + it("should allow reencryption of counter value", async function () { + const input = this.instances.createEncryptedInput(this.contractAddress, this.signers.bob.address); + input.add8(1); // Increment by 1 as an example + const encryptedAmount = await input.encrypt(); + + // Call incrementBy with encrypted amount + const tx = await this.counterContract + .connect(this.signers.bob) + .incrementBy(encryptedAmount.handles[0], encryptedAmount.inputProof); + await tx.wait(); + + // Get the encrypted counter value + const encryptedCounter = await this.counterContract.connect(this.signers.bob).getCounter(); + + const decryptedValue = await reencryptEuint8( + this.signers, + this.instances, + "bob", encryptedCounter, - privateKey, - publicKey, - signature, this.contractAddress, - this.signers.alice.address, ); - // Verify the decrypted value is 1 + // Verify the decrypted value is 1 (since we incremented once) expect(decryptedValue).to.equal(1); }); }); - ``` #### Key additions in testing diff --git a/docs/fundamentals/inputs.md b/docs/fundamentals/inputs.md index 4e41eb1f..2ee85526 100644 --- a/docs/fundamentals/inputs.md +++ b/docs/fundamentals/inputs.md @@ -51,7 +51,7 @@ To interact with such a function, developers can use the [fhevmjs](https://githu import { createInstances } from "../instance"; import { getSigners, initSigners } from "../signers"; -await initSigners(2); // Initialize signers +await initSigners(); // Initialize signers const signers = await getSigners(); const instance = await createInstances(this.signers); @@ -155,16 +155,16 @@ 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"; +import { SepoliaZamaFHEVMConfig } 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 /// @dev Uses TFHE library for fully homomorphic encryption operations /// @custom:experimental This contract is experimental and uses FHE technology -contract EncryptedCounter2 { - euint8 counter; +contract EncryptedCounter2 is SepoliaZamaFHEVMConfig { + euint8 internal counter; - constructor() is MockZamaFHEVMConfig { + constructor() { // Initialize counter with an encrypted zero value counter = TFHE.asEuint8(0); TFHE.allowThis(counter); @@ -182,14 +182,13 @@ contract EncryptedCounter2 { ### Tests of for the Counter contract ```ts -import { createInstances } from "../instance"; +import { createInstance } from "../instance"; import { getSigners, initSigners } from "../signers"; -import { expect } from "chai"; import { ethers } from "hardhat"; describe("EncryptedCounter2", function () { before(async function () { - await initSigners(2); // Initialize signers + await initSigners(); // Initialize signers this.signers = await getSigners(); }); @@ -198,13 +197,13 @@ describe("EncryptedCounter2", function () { this.counterContract = await CounterFactory.connect(this.signers.alice).deploy(); await this.counterContract.waitForDeployment(); this.contractAddress = await this.counterContract.getAddress(); - this.instances = await createInstances(this.signers); // Set up instances for testing + this.instances = await createInstance(); // Set up instances for testing }); it("should increment by arbitrary encrypted amount", async function () { // Create encrypted input for amount to increment by - const input = this.instances.alice.createEncryptedInput(this.contractAddress, this.signers.alice.address); - input.add8(5); // Increment by 5 as an example + const input = this.instances.createEncryptedInput(this.contractAddress, this.signers.alice.address); + input.add8(5); const encryptedAmount = await input.encrypt(); // Call incrementBy with encrypted amount diff --git a/docs/fundamentals/types.md b/docs/fundamentals/types.md index f286f4c9..4b0d6932 100644 --- a/docs/fundamentals/types.md +++ b/docs/fundamentals/types.md @@ -46,71 +46,3 @@ The `TFHE` library currently supports the following encrypted types: {% hint style="info" %} Higher-precision integer types are available in the `TFHE-rs` library and can be added to `fhEVM` as needed. {% endhint %} - -## Casting encrypted types - -The `TFHE` library provides functions to cast between encrypted and unencrypted types, as well as between encrypted types of different precisions. Casting is handled using the `TFHE.asEuintXX()` or `TFHE.asEbool()` methods. - -### Example: casting - -```solidity -euint64 value64 = TFHE.asEuint64(7262); // Cast unencrypted uint64 to encrypted euint64 -euint32 value32 = TFHE.asEuint32(value64); // Cast encrypted euint64 to euint32 -ebool valueBool = TFHE.asEbool(value32); // Cast encrypted euint32 to ebool -``` - -### Supported casting functions - -The table below summarizes the available casting functions: - -| From type | To type | Function | -| --------- | ---------------- | ----------------- | -| `uintX` | `euintX` | `TFHE.asEuintXX` | -| `euintX` | Higher precision | `TFHE.asEuintXX` | -| `euintX` | `ebool` | `TFHE.asEbool` | -| `address` | `eaddress` | `TFHE.asEaddress` | -| `bytesXX` | `ebytesXX` | `TFHE.asEbytesXX` | - -{% hint style="info" %} -Casting between encrypted types is efficient and often necessary when handling data with differing precision requirements. -{% endhint %} - -## Declaring encrypted state variables - -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 - -Instead of using `immutable` or `constant`, declare and initialize encrypted state variables like this: - -#### Inline initialization - -```solidity -euint64 private totalSupply = TFHE.asEuint64(0); -``` - -#### Initialization in constructor - -```solidity -euint64 private totalSupply; - -constructor() { - totalSupply = TFHE.asEuint64(0); -} -``` - -{% hint style="info" %} -**Why?**\ -The `TFHE.asEuintXX()` function is executed at runtime, making `immutable` or `constant` declarations incompatible. -{% endhint %} - -## **Summary** - -The encrypted types in the `TFHE` library are designed to offer security and flexibility when working with confidential data in smart contracts. Key points to remember include: - -- Encrypted integers operate as wrappers over FHE ciphertexts. -- Arithmetic operations are unchecked to preserve confidentiality. -- Type casting is straightforward, with extensive support for converting between encrypted types and unencrypted inputs. -- Encrypted state variables must be initialized at runtime rather than using `immutable` or `constant`. - -By following these guidelines and leveraging the flexibility of the `TFHE` library, developers can seamlessly integrate encrypted types into their smart contract workflows. diff --git a/docs/getting_started/ethereum.md b/docs/getting_started/ethereum.md index 20632414..2b7661f4 100644 --- a/docs/getting_started/ethereum.md +++ b/docs/getting_started/ethereum.md @@ -52,7 +52,7 @@ Choose and inherit the correct configuration based on the environment: - **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. See [configuration](../fundamentals/configure.md) for more details. +Ensure configuration contracts (e.g., `SepoliaZamaFHEVMConfig`, `SepoliaZamaFHEVMConfig`) are inherited correctly to initialize encryption parameters, cryptographic keys, and Gateway addresses. See [configuration](../fundamentals/configure.md) for more details. ### 4. Begin with unencrypted logic diff --git a/docs/getting_started/first_smart_contract.md b/docs/getting_started/first_smart_contract.md index e3faeb9a..f9d6ca47 100644 --- a/docs/getting_started/first_smart_contract.md +++ b/docs/getting_started/first_smart_contract.md @@ -31,7 +31,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"; +import { SepoliaZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; /// @title EncryptedCounter1 /// @notice A basic contract demonstrating the setup of encrypted types @@ -39,9 +39,9 @@ import { MockZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.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 is MockZamaFHEVMConfig { - euint8 counter; - euint8 CONST_ONE; +contract EncryptedCounter1 is SepoliaZamaFHEVMConfig { + euint8 internal counter; + euint8 internal immutable CONST_ONE; constructor() { // Initialize counter with an encrypted zero value @@ -63,22 +63,14 @@ contract EncryptedCounter1 is MockZamaFHEVMConfig { #### How it works 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. + The contract inherits from `SepoliaZamaFHEVMConfig` 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: @@ -110,13 +102,13 @@ There are two notable issues with this contract: With any contracts that you write you will need to write tests as well. You can start by using something like this as a template: ```ts -import { createInstances } from "../instance"; +import { createInstance } from "../instance"; import { getSigners, initSigners } from "../signers"; import { ethers } from "hardhat"; describe("EncryptedCounter1", function () { before(async function () { - await initSigners(2); // Initialize signers + await initSigners(); // Initialize signers this.signers = await getSigners(); }); @@ -125,7 +117,7 @@ describe("EncryptedCounter1", function () { this.counterContract = await CounterFactory.connect(this.signers.alice).deploy(); await this.counterContract.waitForDeployment(); this.contractAddress = await this.counterContract.getAddress(); - this.instances = await createInstances(this.signers); // Set up instances for testing + this.instances = await createInstance(); }); it("should increment the counter", async function () { @@ -158,7 +150,7 @@ The test file demonstrates key concepts for testing fhEVM smart contracts: ``` 3. **Key components**: - - `createInstances()`: Sets up FHE instances for each signer to handle encrypted operations + - `createInstance()`: Sets up FHE instances for each signer to handle encrypted operations - `getSigners()`: Provides test accounts to interact with the contract - `contractFactory.deploy()`: Creates a new contract instance for testing - `tx.wait()`: Ensures transactions are mined before continuing diff --git a/docs/guides/contracts.md b/docs/guides/contracts.md index bacfbd52..3106b6a2 100644 --- a/docs/guides/contracts.md +++ b/docs/guides/contracts.md @@ -25,17 +25,17 @@ pnpm add fhevm-contracts ### 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: +When testing your contracts locally, you can use the `SepoliaZamaFHEVMConfig` 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"; +import { SepoliaZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; +import { ConfidentialERC20 } from "fhevm-contracts/contracts/token/ERC20/ConfidentialERC20.sol"; -contract MyERC20 is MockZamaFHEVMConfig, EncryptedERC20 { - constructor() EncryptedERC20("MyToken", "MYTOKEN") { +contract MyERC20 is SepoliaZamaFHEVMConfig, ConfidentialERC20 { + constructor() ConfidentialERC20("MyToken", "MYTOKEN") { _unsafeMint(1000000, msg.sender); } } @@ -50,10 +50,10 @@ When deploying to Sepolia, you can use the `SepoliaZamaFHEVMConfig` which provid pragma solidity ^0.8.24; import { SepoliaZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol"; -import { EncryptedERC20 } from "fhevm-contracts/contracts/token/ERC20/EncryptedERC20.sol"; +import { ConfidentialERC20 } from "fhevm-contracts/contracts/token/ERC20/ConfidentialERC20.sol"; -contract MyERC20 is SepoliaZamaFHEVMConfig, EncryptedERC20 { - constructor() EncryptedERC20("MyToken", "MYTOKEN") { +contract MyERC20 is SepoliaZamaFHEVMConfig, ConfidentialERC20 { + constructor() ConfidentialERC20("MyToken", "MYTOKEN") { _unsafeMint(1000000, msg.sender); } } @@ -66,13 +66,13 @@ When inheriting from configuration contracts, the order of inheritance is critic βœ… **Correct Order**: ``` -contract MyERC20 is SepoliaZamaFHEVMConfig, EncryptedERC20 { ... } +contract MyERC20 is SepoliaZamaFHEVMConfig, ConfidentialERC20 { ... } ``` ❌ **Wrong order**: ``` -contract MyERC20 is EncryptedERC20, SepoliaZamaFHEVMConfig { ... } +contract MyERC20 is ConfidentialERC20, SepoliaZamaFHEVMConfig { ... } ``` ## Available contracts diff --git a/docs/guides/debug_decrypt.md b/docs/guides/debug_decrypt.md new file mode 100644 index 00000000..01a4c1b4 --- /dev/null +++ b/docs/guides/debug_decrypt.md @@ -0,0 +1,117 @@ +# Debugging with `debug.decrypt[XX]` + +This guide explains how to use the `debug.decrypt[XX]` functions for debugging encrypted data in mocked environments during development with fhEVM. + +> [!WARNING] +> The `debug.decrypt[XX]` functions should not be used in production as they rely on private keys. + +## Overview + +The `debug.decrypt[XX]` functions allow you to decrypt encrypted handles into plaintext values. This feature is useful for debugging encrypted operations such as transfers, balance checks, and other computations involving FHE-encrypted data. + +### Key points + +- **Environment**: The `debug.decrypt[XX]` functions work **only in mocked environments** (e.g., `hardhat` network). +- **Production limitation**: In production, decryption is performed asynchronously via the Gateway and requires an authorized onchain request. +- **Encrypted types**: The `debug.decrypt[XX]` functions supports various encrypted types, including integers, booleans, and `ebytesXX`. +- **Bypass ACL authorization**: The `debug.decrypt[XX]` functions allow decryption without ACL authorization, useful for verifying encrypted operations during development and testing. + +## Supported functions + +### Integer decryption + +Decrypts encrypted integers of different bit-widths (`euint4`, `euint8`, ..., `euint256`). + +| Function Name | Returns | Encrypted Type | +| ------------- | -------- | -------------- | +| `decrypt4` | `bigint` | `euint4` | +| `decrypt8` | `bigint` | `euint8` | +| `decrypt16` | `bigint` | `euint16` | +| `decrypt32` | `bigint` | `euint32` | +| `decrypt64` | `bigint` | `euint64` | +| `decrypt128` | `bigint` | `euint128` | +| `decrypt256` | `bigint` | `euint256` | + +### Boolean decryption + +Decrypts encrypted booleans (`ebool`). + +| Function Name | Returns | Encrypted Type | +| ------------- | --------- | -------------- | +| `decryptBool` | `boolean` | `ebool` | + +### Byte array decryption + +Decrypts encrypted byte arrays of various sizes (`ebytesXX`). + +| Function Name | Returns | Encrypted Type | +| ------------------ | -------- | -------------- | +| `decryptEbytes64` | `string` | `ebytes64` | +| `decryptEbytes128` | `string` | `ebytes128` | +| `decryptEbytes256` | `string` | `ebytes256` | + +### Address decryption + +Decrypts encrypted addresses. + +| Function Name | Returns | Encrypted Type | +| ---------------- | -------- | -------------- | +| `decryptAddress` | `string` | `eaddress` | + +## Function usage + +### Example: decrypting encrypted values + +```typescript +import { debug } from "../utils"; + +// Decrypt a 64-bit encrypted integer +const handle64: bigint = await this.erc20.balanceOf(this.signers.alice); +const plaintextValue: bigint = await debug.decrypt64(handle64); +console.log("Decrypted Balance:", plaintextValue); +``` + +> [!NOTE] +> To utilize the debug functions, import the [utils.ts](https://github.com/zama-ai/fhevm-hardhat-template/blob/main/test/utils.ts) file. + +For a more complete example, refer to the [ConfidentialERC20 test file](https://github.com/zama-ai/fhevm-hardhat-template/blob/f9505a67db31c988f49b6f4210df47ca3ce97841/test/confidentialERC20/ConfidentialERC20.ts#L181-L205). + +### Example: decrypting byte arrays + +```typescript +// Decrypt a 128-byte encrypted value +const ebytes128Handle: bigint = ...; // Get handle for the encrypted bytes +const decryptedBytes: string = await debug.decryptEbytes128(ebytes128Handle); +console.log("Decrypted Bytes:", decryptedBytes); +``` + +## **How it works** + +### Verifying types + +Each decryption function includes a **type verification step** to ensure the provided handle matches the expected encrypted type. If the type is mismatched, an error is thrown. + +```typescript +function verifyType(handle: bigint, expectedType: number) { + const typeCt = handle >> 8n; + if (Number(typeCt % 256n) !== expectedType) { + throw "Wrong encrypted type for the handle"; + } +} +``` + +### Environment checks + +> [!CAUTION] +> The functions only work in the `hardhat` network. Attempting to use them in a production environment will result in an error. + +```typescript +if (network.name !== "hardhat") { + throw Error("This function can only be called in mocked mode"); +} +``` + +## **Best practices** + +- **Use only for debugging**: These functions require access to private keys and are meant exclusively for local testing and debugging. +- **Production decryption**: For production, always use the asynchronous Gateway-based decryption. diff --git a/docs/guides/error_handling.md b/docs/guides/error_handling.md index f3945ebf..9666765b 100644 --- a/docs/guides/error_handling.md +++ b/docs/guides/error_handling.md @@ -18,7 +18,7 @@ To address these challenges, implement an **error handler** that records the mos For a complete implementation of error handling, see our reference contracts: - [EncryptedErrors.sol](https://github.com/zama-ai/fhevm-contracts/blob/main/contracts/utils/EncryptedErrors.sol) - Base error handling contract -- [EncryptedERC20WithErrors.sol](https://github.com/zama-ai/fhevm-contracts/blob/main/contracts/token/ERC20/extensions/ConfidentialERC20WithErrors.sol) - Example usage in an ERC20 token +- [ConfidentialERC20WithErrors.sol](https://github.com/zama-ai/fhevm-contracts/blob/main/contracts/token/ERC20/extensions/ConfidentialERC20WithErrors.sol) - Example usage in an ERC20 token The following contract demonstrates how to implement and use an error handler: diff --git a/docs/guides/frontend/webpack.md b/docs/guides/frontend/webpack.md index 38a2c234..b0ed7b22 100644 --- a/docs/guides/frontend/webpack.md +++ b/docs/guides/frontend/webpack.md @@ -18,9 +18,13 @@ resolve: { }, ``` -## Error message: ReferenceError: Buffer is not defined +## Buffer not defined -If you encounter this issue with the Node Buffer object, you should offer an alternative solution. Similar issues might arise with different Node objects. In such cases, install the corresponding browserified npm package and include the fallback as follows. +**Error message:** `ReferenceError: Buffer is not defined` + +**Cause:** This error occurs when the Node.js `Buffer` object is used in a browser environment where it is not natively available. + +**Possible sultions:** To resolve this issue, you need to provide browser-compatible fallbacks for Node.js core modules. Install the necessary browserified npm packages and configure Webpack to use these fallbacks. ```javascript resolve: { @@ -31,22 +35,26 @@ resolve: { path: require.resolve('path-browserify'), }, }, - ``` ## Issue with importing ESM version -With a bundler such as Webpack or Rollup, imports will be replaced with the version mentioned in the `"browser"` field of the `package.json`. If you encounter issue with typing, you can use this [tsconfig.json](https://github.com/zama-ai/fhevmjs-react-template/blob/main/tsconfig.json) using TypeScript 5. +**Error message:** Issues with importing ESM version -If you encounter any other issue, you can force import of the browser package. +**Cause:** With a bundler such as Webpack or Rollup, imports will be replaced with the version mentioned in the `"browser"` field of the `package.json`. This can cause issues with typing. -```javascript -import { initFhevm, createInstance } from "fhevmjs/web"; -``` +**Possible solutions:** + +- If you encounter issues with typing, you can use this [tsconfig.json](https://github.com/zama-ai/fhevmjs-react-template/blob/main/tsconfig.json) using TypeScript 5. +- If you encounter any other issue, you can force import of the browser package. ## Use bundled version -If you have an issue with bundling the library (for example with some SSR framework), you can use the prebundled version available in `fhevmjs/bundle`. Just embed the library with a `