Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Our library compiles seamlessly with the traditional Solidity compiler and is generally compatible with traditional Solidity tools. However, it's important to note that the execution is designed to function exclusively on a fhEVM. As a result, this library is not intended for deployment on a classic EVM, such as Goerli or Ganache.
To get started with fhEVM Solidity Library, you need to install it as a dependency in your JavaScript project. You can do this using npm (Node Package Manager) or Yarn. Open your terminal and navigate to your project's directory, then run one of the following commands:
This will download and install the fhEVM Solidity Library and its dependencies into your project.
1/ For quick prototyping of a specific feature, use the Zama version of the Remix IDE. This will let you quickly deploy a contract on the devnet via Metamask, and interact easily with it through the Remix UI. Otherwise, for a bigger project, you should use our custom fhevm-hardhat-template
repository. Hardhat is a popular development environment for Solidity developers and will let you test and deploy your contracts to the fhEVM using TypeScript.
2/ A good first step is to start with an unencrypted version of the contract you want to implement, as you would usually do on a regular EVM chain. It is easier to reason first on cleartext variables, before thinking on how to add confidentialy.
3/ When you're ready, you can start to add confidentiality by using the TFHE
solidity library. Typically, this would involve converting some uintX
types to euintX
, as well as following all the detailed advices that we gave in the pitfalls to avoid and best practises section of the documentation. For inspiration, you can take a look at the examples inside the fhevm
repository. If you're using the Hardhat template, read the advices that we gave in the Hardhat section.
The best way to start writing smart contracts with fhEVM is to use our Hardhat template.
It allows you to start a fhEVM docker image and run your smart contract on it. Read the README for more information.
When developing confidential contracts, we recommend to use first the mocked version of fhEVM for faster testing with pnpm test:mock
and coverage computation via pnpm coverage:mock
, this will lead to a better developer experience. However, keep in mind that the mocked fhEVM has some limitations and discrepencies compared to the real fhEVM node, as explained in the warning section at the end of this section.
It's essential to run tests of the final contract version using the real fhEVM. You can do this by running pnpm test
before deployment.
For faster testing iterations, instead of launching all the tests on the local fhEVM node via pnpm test
or npx hardhat test
which could last several minutes, you could use instead a mocked version of the TFHE.sol
library. The same tests should (almost always) pass, as is, without any modification: neither the javascript files neither the solidity files need to be changed between the mocked and the real version. The mocked mode does not actually use encryption for encrypted types and runs the tests on a local hardhat node which is implementing the original EVM (i.e non-fhEVM).
To run the mocked tests use either:
Or equivalently:
In mocked mode, all tests should pass in few seconds instead of few minutes, allowing a better developer experience.
Furthermore, getting the coverage of tests is only possible in mocked mode. Just use the following command:
Or equivalently:
Then open the file coverage/index.html
. This will allow increased security by pointing out missing branches not covered yet by the current test suite.
⚠️ Warning : Notice that, due to intrinsic limitations of the original EVM, the mocked version differ in few corner cases from the real fhEVM, the most important change is the TFHE.isInitialized
method which will always return true
in the mocked version. Another big difference in mocked mode, compared to the real fhEVM implementation, is that there is no ciphertext verification neither checking that a ciphertext has been honestly obtained in the mocked version (see section 4
of the whitepaper). 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 pnpm test
or npx hardhat test
.
Random encrypted integers can be generated fully on-chain.
That can only be done during transactions and not on an eth_call
RPC method, because PRNG state needs to be mutated on-chain during generation.
WARNING: Not for use in production! Currently, integers are generated in the plain via a PRNG whose seed and state are public, with the state being on-chain. An FHE-based PRNG is coming soon, where the seed and state will be encrypted.
The fhEVM does not work with Foundry as Foundry employs its own EVM, preventing us from incorporating a mock for our precompiled contract. An ongoing discussion is exploring the possibility of incorporating a plugin system for precompiles, which could potentially pave the way for the utilization of Foundry at a later stage.
However, you could still use Foundry with the mocked version of the fhEVM, but please be aware that this approach is NOT recommended, since the mocked version is not fully equivalent to the real fhEVM node's implementation (see warning in hardhat). In order to do this, you will need to rename your TFHE.sol
imports from fhevm/lib/TFHE.sol
to fhevm/mocks/TFHE.sol
in your solidity source files.
The result of comparison operations is of type ebool
. Typical boolean operations are not supported for this type, because it is an encrypted boolean.
fhEVM provides a method which acts as a ternary operator on encrypted integers. This method is called cmux.
It is important to keep in mind that each time we assign a value using TFHE.cmux
, the value changes, even if the plaintext value remains the same.
If a condition is not satisfied, the transaction will not be reverted, potentially posing a challenge when attempting to communicate issues to users. A recommended approach to address this is by implementing an error handler in which the contract stores the latest error information for all wallets.
We allow explicit decryption requests for any encrypted type. The values are decrypted with the network private key (the threshold decryption protocol is in the works).
For now, a TFHE.decrypt
is pretty cheap, making it tempting to use constructs like if(TFHE.decrypt(encryptedBool))
. However, it is recommended to avoid this approach, as in the future, each decryption will trigger an external call, introducing latency and incurring gas costs. Instead, use cmux operator to handle conditions.
For the same reason, you should replace a require(TFHE.decrypt(encryptedBool1) && TFHE.decrypt(encryptedBool2));
with a TFHE.decrypt(TFHE.and(encryptedBool1, encryptedBool2));
to limit decryption calls.
The reencrypt functions takes as inputs a ciphertext and a public encryption key (namely, a NaCl box).
During reencryption, the ciphertext is decrypted using the network private key (the threshold decryption protocol is in the works). Then, the decrypted result is encrypted under the user-provided public encryption key. The result of this encryption is sent back to the caller as bytes memory
.
It is also possible to provide a default value to the reencrypt
function. In this case, if the provided ciphertext is not initialized (i.e., if the ciphertext handle is 0
), the function will return an encryption of the provided default value.
NOTE: If one of the following operations is called with an uninitialized ciphertext handle as an operand, this handle will be made to point to a trivial encryption of
0
before the operation is executed.
In the example above (balanceOf
), this view function need to validate the user to prevent anyone to reencrypt any user's balance. To prevent this, the user provides a signature of the given public key. The best way to do it is to use EIP-712 standard. Since this is something very useful, fhEVM library provide an abstract to use in your contract:
When a contract uses Reencrypt
abstract, a modifier is available to check user signature.
This signature can be generated on client side using fhevmjs library.
You can get 10 Zama token on https://faucet.zama.ai/.
You can use Remix to interact with a blockchain using fhEVM. If you want to send an encrypted input, you need to encrypt it with fhevmjs CLI tool for example. It becomes more complex if you want to reencrypt a value directly in Remix.
To avoid this problem, we developed a version of Remix IDE with these two missing features:
Encryption of input
Generation of public key and signature for reencryption and decryption.
You can use it on https://remix.zama.ai.
To import TFHE library, simply import it at the top of your contract.
import "fhevm/lib/TFHE.sol";
Be sure to be on the correct network before deploying your contract
````
Here are the main steps from the official guide provided by Metamask:
Add these informations to access to blockchain
📙 White paper | 📁 Github | 💛 Community support | 🟨 Zama Bounty Program
There used to be a dilemma in blockchain: keep your application and user data on-chain, allowing everyone to see it, or keep it privately off-chain and lose contract composability. Thanks to a breakthrough in homomorphic encryption, Zama’s fhEVM makes it possible to run confidential smart contracts on encrypted data, guaranteeing both confidentiality and composability.
fhEVM contracts are simple solidity contracts that are built using traditional solidity toolchains. Developers can use the euint data types to mark which part of their contracts should be private. All the logic for access control of encrypted states is defined by developers in their smart contracts.
Tokenization: Swap tokens and RWAs on-chain without others seeing the amounts.
Blind auctions: Bid on items without revealing the amount or the winner.
On-chain games: Keep moves, selections, cards, or items hidden until ready to reveal.
Confidential voting: Prevents bribery and blackmailing by keeping votes private.
Encrypted DIDs: Store identities on-chain and generate attestations without ZK.
Private transfers: Keep balances and amounts private, without using mixers.
🎥 Workshop during ETHcc [by Morten Dahl — Zama]
🎥 How to Write Confidential Smart Contracts Using Zama's fhEVM [by Clément Danjou (Zama)]
📃 Programmable Privacy and Onchain Compliance using Homomorphic Encryption [by Rand Hindi and Clément Danjou — Zama]
📃 Confidential ERC-20 Tokens Using Homomorphic Encryption [by [Clément Danjou — Zama]
📃 On-chain Blind Auctions Using Homomorphic Encryption [by Clément Danjou — Zama]
🖥️ Darkpool [by Owen Murovec]
The TFHE
library provides encrypted integer types and a type system that is checked both at compile time and at run time.
Encrypted integers behave as much as possible as Solidity's integer types. Currently, however, behaviour such as "revert on overflow" is not supported as this would leak some information about the encrypted value. Therefore, arithmetic on e(u)int
types is unchecked, i.e. there is wrap-around on overflow.
Encrypted integers with overflow checking are coming soon to the TFHE
library. They will allow reversal in case of an overflow, but will leak some information about the operands.
In terms of implementation in the fhEVM
, encrypted integers take the form of FHE ciphertexts. The TFHE
library abstracts away that and, instead, exposes ciphertext handles to smart contract developers. The e(u)int
types are wrappers over these handles.
The following encrypted data types are defined:
type | supported |
---|---|
Higher-precision integers are supported in the TFHE-rs
library and can be added as needed to fhEVM
.
NOTE 1: The
ebool
type is currently implemented as aneuint8
. A more optimized native boolean type will replaceeuint8
.
When users send serialized ciphertexts as bytes
to the blockchain, they first need to be converted to the respective encrypted integer type. Conversion verifies if the ciphertext is well-formed and includes proof verification. These steps prevent usage of arbitrary inputs. For example, following functions are provided for ebool
, euint8
, euint16
and euint32
:
TFHE.asEbool(bytes ciphertext)
verifies the provided ciphertext and returns an ebool
TFHE.asEuint8(bytes ciphertext)
verifies the provided ciphertext and returns an euint8
TFHE.asEuint16(bytes ciphertext)
verifies the provided ciphertext and returns an euint16
TFHE.asEuint32(bytes ciphertext)
verifies the provided ciphertext and returns an euint32
... more functions for the respective encrypted integer types
If you require a state variable that utilizes these encrypted types, you cannot directly assign the value. In Solidity, the compiler attempts to ascertain the value of TFHE.asEuintXX(yy)
during compilation, which is not feasible because asEuintXX()
invokes a precompiled contract. To address this challenge, you should declare your property and subsequently assign its value within the constructor. Also, please be aware that you should never declare encrypted types as either constant or immutable variables, as these variables need to be stored in the privileged storage of the fhEVM, which is not compatible with constant variable types.
FHE operations are typically more computationally expensive than classical operations due to their inherent complexity. As a reference, here is an approximation of the gas cost associated with each operation.
function name | ebool/euint8 | euint16 | euint32 |
---|
When you call estimate gas method, we can’t determine accurately the gas usage if your function uses TFHE.decrypt
. During gas estimation, all TFHE.decrypt()
will return 1
.
require(TFHE.decrypt(ebool));
will be ok but require(!TFHE.decrypt(ebool));
will fail during estimation (revert transaction)
A loop, where you expect a decrypt to be false to break, will never end in gas estimate method (and fails), since the decrypt will always return 1
(true)
On the other hand, if your loop should last 2 or 3 cycles, until the value is 1, the estimation will be below.
If you have branches (if/else) based on a decryption, the estimation will use the branch running when the decryption is 1
While it’s challenging to accurately estimate gas consumption when using TFHE.decrypt
, we strongly encourage you to take this into consideration.
A possible solution is to overestimate your gas estimation. You can take this function (with ethers.js) as an example where we multiply the gas limit by 1.2
.
The current devnet has a gas limit of 10,000,000. If you send a transaction exceeding this limit, it won't be executed. Consequently, your wallet won't be able to emit a new transaction. To address this, emit a new transaction with the same nonce but the correct gas limit. In Metamask, you can enforce the use of a specific nonce by enabling the feature in 'Advanced Settings'.
fhevmjs
uses ESM format. You need to set the .
To use the library in your project, you need to load the WASM of first with initFhevm
.
In the codebase, there is a new URL('tfhe_bg.wasm')
which triggers a resolve by Webpack. If you encounter an issue, you can add a fallback for this file by adding a resolve configuration in your webpack.config.js
:
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.
If you encounter any other issue, you can force import of the browser package.
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 <script>
tag and you're good to go.
fhevmjs
is working out of the box and we recommend you to use it. We also provide three GitHub templates to start your project with everything set.
You can use to start an application with fhevmjs, using Vite + React + TypeScript.
You can also use to start an application with fhevmjs, using Vite + Vue + TypeScript.
You can also use to start an application with fhevmjs, using Next + TypeScript.
The TFHE
library defines the following operations with FHE ciphertexts:
name | function name | symbol | type |
---|
NOTE 1: Random encrypted integers that are generated fully on-chain. Currently, implemented as a mockup by using a PRNG in the plain. Not for use in production!
The library provides a set of functions to encrypt integers of various sizes (8, 16, and 32 bits) using the blockchain's public key. These encrypted integers can then be securely used as parameters for smart contract methods within the blockchain ecosystem.
Welcome to the documentation for fhevmjs, a JavaScript library that enables interaction with blockchain using Zama's technology! This comprehensive guide provides developers with detailed information on encryption of data using TFHE (Fully Homomorphic Encryption over the Torus) and generation of EIP-719 tokens for reencrypt data.
To get started with fhevmjs, you need to install it as a dependency in your JavaScript project. You can do this using npm, Yarn or pnpm. Open your terminal and navigate to your project's directory, then run one of the following commands:
This will download and install the fhevmjs library and its dependencies into your project.
fhevmjs provides two features:
Encrypt an input with the blockchain's FHE public key
Generate a private key and a public key to provide to TFHE.reencrypt()
Before using these features, you need to create an instance and provide some informations:
The blockchain chainId
The blockchain's FHE public key
You can get this information directly from the blockchain you're using. For example with ethers
:
Important: Since the instance memorizes user's signature, you need to refresh the instance if the user uses another wallet address. Otherwise, you will encounter issue during reencryption.
You can store this object in the user's local storage, enabling you to load it in the next user session. You must save this information per wallet since it contains the user's signature.
You can load previously stored keypairs to initialize the instance.
fhevmjs include a Command-Line Interface (CLI) tool. With this handy utility, you can encrypt 8/16/32bits integer with the blockchain's FHE public key. To get started with fhevmjs CLI, first, ensure you have Node.js installed on your system. Next, install the fhevmjs package globally using the '-g' flag, which allows you to access the CLI tool from any directory:
Once installed, fhevm
command should be available. You can get all commands and options available with fhevm help
or fhevm encrypt help
.
Encrypt 71721075 as 32bits integer:
[by Morten Dahl — Zama]
[by Clément Danjou (Zama)]
[by Rand Hindi and Clément Danjou — Zama]
[by [Clément Danjou — Zama]
[by Clément Danjou — Zama]
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 parapgraph 4.4 of ) 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, this code :
✅ Should be replaced by this snippet:
Declaring an encrypted state variable as public exposes the variable to any external untrusted smart contract to access and potentially decrypt them, compromising their confidentiality.
❌ In summary, never write in production:
✅ Instead, you should declare the state variable as follow:
In this last snippet, the internal
keyword could have been omitted (state variables are internal by default) or alternatively have been replaced by private
.
Any use of decryption should be avoided as much as possible. Current version of TFHE.decrypt
will soon be deprecated and get replaced by an asynchronous version, so please consider this operator as a very expensive one which should be used only if absolutely necessary.
Whenever your code contains a branch depending on the result of a decryption, we recommend to replace it by a TFHE.cmux
.
❌ For instance, instead of:
✅ We recommend instead to use the following pattern:
The previous paragraph emphasized that branch logic should rely as much as possible on TFHE.cmux
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:
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 this type of loop because it might require many decryption operations, and in the example given, we're also leaking how much was added to x
, which may not be intended behavior.:
If your code logic requires looping on an encrypted boolean condition, we highly suggest to try to replace it by a finite loop with an appropriate constant maximum number of steps and use TFHE.cmux
inside the loop.
✅ For example, the previous code could maybe be replaced by the following snippet:
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.
❌ For example, this snippet cost way more in gas:
✅ Than this one:
Despite both leading to the same encrypted result!
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:
✅ But you can fix this issue by using TFHE.cmux
to cancel the mint in case of an overflow:
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.
name | description | ETA |
---|
name | function name | type | ETA |
---|
NOTE 1: Methods prefixed with
safe
will do an overflow check by decrypting an overflow bit and revert if that bit is true.
NOTE 2: Random encrypted integers that are generated fully on-chain. Currently, implemented as a mockup by using a PRNG in the plain. Not for use in production!
When user needs to access encrypted data, there are two solution for the smart contract developer:
Return a decryption of this value. In this case, the becomes public and the confidentiality is compromised.
Return a reencryption of this value. In this case, the user provides a public key, the value will be reencrypted from the blockchain's FHE public key to this public key.
A value reencryption is accessible through a view function. However, it's important to note that there's a potential vulnerability where msg.sender
can be spoofed, and you cannot guarantee that the msg.sender
truly represents the user.
To prevent this issue, the smart contract can use the . It describes how data is structured, hashed, and signed. By utilizing this data format and having it signed by the user, a secure process of reencrypting data becomes possible within a smart contract. The signed structure includes the necessary information, including the public key, which allows for seamless reencryption of the data.
The user provides the signature of the EIP-712 object and the public key
The contract verify the signature by generating the EIP-712 with the provided public key. The signature must match the msg.sender
If the signature match, the contract can return the reencryption of the value with the provided public key
fhevmjs
provides a convenient function that generates this structured object and store user's signatures.
You can generate the data to sign:
When generating the public key using generatePublicKey
, the corresponding private key is kept by the fhEVM instance and linked to the specified contract. To decrypt a value using the user's private key, you only need to provide the contract address and the encrypted value.
Upon the user's signing of the public key, it is advisable to keep the signature for potential use in other reencryption requests. The library offers the setPublicKeySignature
method to link this signature with the contract's public key.
When the signature is saved, you can reuse it with getPublicKey()
.
You can merge these two functions to create one that returns both the public key and the signature. To check if a signed key pair already exists for a specific contract, you can use the hasKeypair()
method provided by the instance.
Note: only signed keypairs are returned by hasKeypair()
and getPublicKey
.
The functions exposed by the TFHE
Solidity library come in various shapes and sizes in order to facilitate developer experience. For example, most binary operators (e.g., add
) can take as input any combination of the supported data types.
In the fhEVM
, FHE operations are only defined on same-type operands. Implicit upcasting will be done automatically, if necessary.
Most binary operators are also defined with a mix of ciphertext and plaintext operands, under the condition that the size of the plaintext operand is at most the size of the encrypted operand. For example, add(uint8 a, euint8 b)
is defined but add(uint32 a, euint16 b)
is not. Note that these ciphertext-plaintext operations may take less time to compute than ciphertext-ciphertext operations.
asEuint
The asEuint
functions serve three purposes:
verify ciphertext bytes and return a valid handle to the calling smart contract;
cast a euintX
typed ciphertext to a euintY
typed ciphertext, where X != Y
;
trivially encrypt a plaintext value.
The first case is used to process encrypted inputs, e.g. user-provided ciphertexts. Those are generally included in a transaction payload.
The second case is self-explanatory. When X > Y
, the most significant bits are dropped. When X < Y
, the ciphertext is padded to the left with trivial encryptions of 0
.
The third case is used to "encrypt" a public value so that it can be used as a ciphertext. Note that what we call a trivial encryption is not secure in any sense. When trivially encrypting a plaintext value, this value is still visible in the ciphertext bytes. More information about trivial encryption can be found .
asEbool
The asEbool
functions behave similarly to the asEuint
functions, but for encrypted boolean values.
During reencryption, the ciphertext is decrypted using the network private key (the threshold decryption protocol is in the works). Then, the decrypted result is encrypted under the user-provided public encryption key. The result of this encryption is sent back to the caller as bytes memory
.
It is also possible to provide a default value to the reencrypt
function. In this case, if the provided ciphertext is not initialized (i.e., if the ciphertext handle is 0
), the function will return an encryption of the provided default value.
NOTE: If one of the following operations is called with an uninitialized ciphertext handle as an operand, this handle will be made to point to a trivial encryption of
0
before the operation is executed.
add
, sub
, mul
, div
, rem
)Performs the operation homomorphically.
Note that division/remainder only support plaintext divisors.
AND
, OR
, XOR
)Unlike other binary operations, bitwise operations do not natively accept a mix of ciphertext and plaintext inputs. To ease developer experience, the TFHE
library adds function overloads for these operations. Such overloads implicitely do a trivial encryption before actually calling the operation function, as shown in the examples below.
<<
, >>
)Shifts the bits of the base two representation of a
by b
positions.
eq
, ne
, ge
, gt
, le
, lt
)Note that in the case of ciphertext-plaintext operations, since our backend only accepts plaintext right operands, calling the operation with a plaintext left operand will actually invert the operand order and call the opposite comparison.
The result of comparison operations is an encrypted boolean (ebool
). In the backend, the boolean is represented by an encrypted unsinged integer of bit width 8, but this is abstracted away by the Solidity library.
cmux
)This operator takes three inputs. The first input b
is of type ebool
and the two others of type euintX
. If b
is an encryption of true
, the first integer parameter is returned. Otherwise, the second integer parameter is returned.
min
, max
Returns the minimum (resp. maximum) of the two given values.
neg
, not
)There are two unary operators: neg
(-
) and not
(!
). Note that since we work with unsigned integers, the result of negation is interpreted as the modular opposite. The not
operator returns the value obtained after flipping all the bits of the operand.
Random encrypted integers can be generated fully on-chain.
That can only be done during transactions and not on an eth_call
RPC method, because PRNG state needs to be mutated on-chain during generation.
WARNING: Not for use in production! Currently, integers are generated in the plain via a PRNG whose seed and state are public, with the state being on-chain. An FHE-based PRNG is coming soon, where the seed and state will be encrypted.
Fields | Value |
---|---|
Fields | Value |
---|---|
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 using TypeScript 5.
Overloaded operators +
, -
, *
, &
, ... on encrypted integers are supported (). As of now, overloaded operators will call the versions without an overflow check.
More information about the supported operations can be found in the page or in the .
If you find yourself in search of a missing feature, we encourage you to for upcoming developments. Alternatively, don't hesitate to reach out to us on Discord or visit our community forum.
When a user generate and sign an for a contract, you can export these tokens with instance.serializeKeypairs()
. This method will return all keypairs and signature associated with a contract.
If a view function is using TFHE.reencrypt
it is mandatory to protect its access to not leak confidentiality, for instance this is doable easily via the onlySignedPublicKey
modifier imported from "fhevm/abstracts/Reencrypt.sol"
. See the example from the . Failing to address this allows anyone to reencrypt another person's ciphertext. This vulnerability comes from the ability to impersonate any msg.sender
address during a static call to a view function, as it does not require a signature, unlike transactions.
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 to discover which operators support scalar operands and compare the gas saved between both versions: all-encrypted operands vs scalar.
The reencrypt functions takes as inputs a ciphertext and a public encryption key (namely, a ).
NOTE: More information about the behavior of these operators can be found at the .
JSON-RPC
http://127.0.0.1:8545
Websocket
http://127.0.0.1:8546
Network Name
Zama Network
New RPC URL
https://devnet.zama.ai
Chain ID
8009
Currency symbol
ZAMA
Block explorer URL (Optional)
https://main.explorer.zama.ai
Network Name
Zama Local
New RPC URL
http://localhost:8545/
Chain ID
9000
Currency symbol
ZAMA
Block explorer URL (Optional)
ebool
yes (1)
euint8
yes
euint16
yes
euint32
yes
euint64
no, coming soon
eint8
no, coming soon
eint16
no, coming soon
eint32
no, coming soon
eint64
no, coming soon
| 120,000 | 150,000 | 180,000 |
| 120,000 | 150,000 | 180,000 |
| 120,000 | 150,000 | 180,000 |
| 120,000 | 150,000 | 180,000 |
| 200,000 | 260,000 | 380,000 |
| 135,000 | 140,000 | 170,000 |
| 450,000 | 500,000 | 550,000 |
| 450,000 | 500,000 | 550,000 |
| 30,000 | 33,000 | 36,000 |
| 30,000 | 33,000 | 36,000 |
| 30,000 | 33,000 | 36,000 |
| 150,000 | 180,000 | 210,000 |
| 32,000 | 32,000 | 32,000 |
| 150,000 | 180,000 | 210,000 |
| 32,000 | 32,000 | 32,000 |
| 56,000 | 67,000 | 89,000 |
| 56,000 | 67,000 | 89,000 |
| 56,000 | 67,000 | 89,000 |
| 56,000 | 67,000 | 89,000 |
| 56,000 | 67,000 | 89,000 |
| 56,000 | 67,000 | 89,000 |
| 220,000 | 280,000 | 340,000 |
| 220,000 | 280,000 | 340,000 |
| 29,000 | 31,000 | 33,000 |
| 29,000 | 31,000 | 33,000 |
| 60,000 | 65,000 | 70,000 |
| 500,000 | 500,000 | 500,000 |
| 100,000 | 100,000 | 100,000 |
Add |
|
| Binary |
Sub |
|
| Binary |
Mul |
|
| Binary |
Div (plaintext divisor) |
| Binary |
Rem (plaintext divisor) |
| Binary |
BitAnd |
|
| Binary |
BitOr |
|
| Binary |
BitXor |
|
| Binary |
Shift Right |
| Binary |
Shift Left |
| Binary |
Equal |
| Binary |
Not equal |
| Binary |
Greater than or equal |
| Binary |
Greater than |
| Binary |
Less than or equal |
| Binary |
Less than |
| Binary |
Min |
| Binary |
Max |
| Binary |
Neg |
|
| Unary |
Not |
|
| Unary |
Cmux |
| Ternary |
Decrypt |
| Decryption |
Reencrypt |
| Reencryption |
Random unsigned int (mockup) |
| Random |
64bits | Add euint64 | Q2 '24 |
Encrypted address | Add new type | Q2 '24 |
Key Management System | Decrypt through a centralized KMS | Q2 '24 |
Proof for inputs | Generate a proof for every encrypted input | Q3 '24 |
Threshold decryption | Use threshold decryption | Q3 '24 |
Add w/ overflow check |
| Binary, Decryption | Coming soon (1) |
Sub w/ overflow check |
| Binary, Decryption | Coming soon (1) |
Mul w/ overflow check |
| Binary, Decryption | Coming soon (1) |
Div |
| Binary | - |
Rem |
| Binary | - |
Random unsigned int |
| Random | - |
Random signed int |
| Random | - |
Set inclusion |
| Binary | - |