Skip to content

Commit

Permalink
docs: update Integration guide and FheLib example
Browse files Browse the repository at this point in the history
  • Loading branch information
dartdart26 committed Aug 14, 2024
1 parent eb04670 commit a96f6e4
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 48 deletions.
25 changes: 7 additions & 18 deletions docs/getting_started/FheLib.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
# FheLib

`FheLib` is a library implemented inside fhevm-go. It offers FHE-related functionalities such as homomorphic operations, decryption/reencryption requests and so on. FheLib is exposed as a single `precompiled` contract (or a `precompile` for short) that is integrated into the underlying blockchain.
`FheLib` is a library implemented inside fhevm-go. It offers FHE-related functionalities such as homomorphic operations, input verification and so on. FheLib is exposed as a single `precompiled` contract (or a `precompile` for short) that is integrated into the underlying blockchain.

FheLib functions can be called by calling the FheLib precompile with a respective EVM function selector.

This page describes the required inputs, behaviours and outputs of some of these functions.

## GetCiphertext Function (selector: e4b808cb)
## GetCiphertext Function (selector: ff627e77)

The `GetCiphertext` function returns a serialized TFHE ciphertext from protected storage given:
* contract address where the ciphertext is stored at
The `GetCiphertext` function returns a serialized TFHE ciphertext given:
* the ebool/e(u)int value (also called a handle) for which the ciphertext is requested

GetCiphertext only works via the `eth_call` RPC.
Expand All @@ -23,30 +22,20 @@ import json
# This is the address of the FheLib precompile. This value is hardcoded per blockchain.
fhe_lib_precompile_address = "0x000000000000000000000000000000000000005d"

# The contract address where the ciphertext is stored at.
contract_address = "ACD7Be4EBF68Bf2A5b6eB0CaFb15460C169BC459"
# 12 bytes of 0s for padding the contract address.
address_zero_padding = "000000000000000000000000"

# The ebool/e(u)int value for which the ciphertext is requested.
handle = "f038cdc8bf630e239f143abeb039b91ec82ec17a8460582e7a409fa551030c06"

# The function selector of GetCiphertext.
get_ciphertext_selector = "e4b808cb"
get_ciphertext_selector = "ff627e77"

# Call the FheLib precompile with `data` being the concatenation of:
# - getCiphertext function selector;
# - 12 bytes of 0s to padd the contract address;
# - contract address;
# - the handle to the ciphertext.
# Call the FheLib precompile with `data` being the handle to the ciphertext.
payload = {
"jsonrpc": "2.0",
"method": "eth_call",
"params": [
{
"to": fhe_lib_precompile_address,
"data": "0x" + get_ciphertext_selector + address_zero_padding +
contract_address + handle
"data": "0x" + handle
},
"latest"
],
Expand All @@ -60,4 +49,4 @@ resp = json.loads(con.getresponse().read())

# Remove leading "0x" and decode hex to get a byte buffer with the ciphertext.
ciphertext = bytes.fromhex(resp["result"][2:])
```
```
34 changes: 33 additions & 1 deletion docs/getting_started/Integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig

- Initialize `isGasEstimation` using `config.IsGasEstimation`
- Initialize `isEthCall` using `config.IsEthCall`
- Initialize `fhevmEnvironment` with `FhevmImplementation{interpreter: nil, logger: &fhevm.DefaultLogger{}, data: fhevm.NewFhevmData(), params: fhevm.DefaultFhevmParams()}`
- Initialize `fhevmEnvironment` with `FhevmImplementation{interpreter: nil, logger: fhevm.NewDefaultLogger(), data: fhevm.NewFhevmData(), params: fhevm.DefaultFhevmParams()}`
- After initializing `evm.interpreter` make sure to point `fhevmEnvironment` to it `evm.fhevmEnvironment.interpreter = evm.interpreter` then initialize it `fhevm.InitFhevm(&evm.fhevmEnvironment)`
#### Update RunPrecompiledContract
Expand All @@ -143,6 +143,38 @@ to:
RunPrecompiledContract(p, evm, caller.Address(), addr, input, gas)
```

#### Update Create() and Create2() functions

Add code to create ciphertext storage:

```go
// Create creates a new contract using code as deployment code.
func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
contractAddr = crypto.CreateAddress(caller.Address(), evm.StateDB.GetNonce(caller.Address()))
// Create the ciphertext storage if not already created.
if evm.StateDB.GetNonce(fhevm.CiphertextStorageAddress) == 0 {
evm.StateDB.CreateAccount(fhevm.CiphertextStorageAddress)
evm.StateDB.SetNonce(fhevm.CiphertextStorageAddress, 1)
}
return evm.create(caller, &codeAndHash{code: code}, gas, value, contractAddr, CREATE)
}

// Create2 creates a new contract using code as deployment code.
//
// The different between Create2 with Create is Create2 uses keccak256(0xff ++ msg.sender ++ salt ++ keccak256(init_code))[12:]
// instead of the usual sender-and-nonce-hash as the address where the contract is initialized at.
func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *big.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
codeAndHash := &codeAndHash{code: code}
contractAddr = crypto.CreateAddress2(caller.Address(), salt.Bytes32(), codeAndHash.Hash().Bytes())
// Create the ciphertext storage if not already created.
if evm.StateDB.GetNonce(fhevm.CiphertextStorageAddress) == 0 {
evm.StateDB.CreateAccount(fhevm.CiphertextStorageAddress)
evm.StateDB.SetNonce(fhevm.CiphertextStorageAddress, 1)
}
return evm.create(caller, codeAndHash, gas, endowment, contractAddr, CREATE2)
}
```

#### Implement EVMEnvironment interface

Now implement the `fhevm.EVMEnvironment` interface for `FhevmImplementation`:
Expand Down
29 changes: 0 additions & 29 deletions fhevm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@ package fhevm

import (
"log/slog"
"math/big"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/holiman/uint256"
fhevm_crypto "github.com/zama-ai/fhevm-go/fhevm/crypto"
"github.com/zama-ai/fhevm-go/fhevm/tfhe"
)

Expand Down Expand Up @@ -67,30 +65,3 @@ func insertRandomCiphertext(environment EVMEnvironment, t tfhe.FheUintType) []by
}

func InitFhevm(accessibleState EVMEnvironment) {}

func Create(evm EVMEnvironment, caller common.Address, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
contractAddr = crypto.CreateAddress(caller, evm.GetNonce(caller))
protectedStorageAddr := fhevm_crypto.CreateProtectedStorageContractAddress(contractAddr)
_, _, leftOverGas, err = evm.CreateContract(protectedStorageAddrCallerAddr, nil, gas, big.NewInt(0), protectedStorageAddr)
if err != nil {
ret = nil
contractAddr = common.Address{}
return
}
// TODO: consider reverting changes to `protectedStorageAddr` if actual contract creation fails.
return evm.CreateContract(caller, code, leftOverGas, value, contractAddr)
}

func Create2(evm EVMEnvironment, caller common.Address, code []byte, gas uint64, endowment *big.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
codeHash := crypto.Keccak256Hash(code)
contractAddr = crypto.CreateAddress2(caller, salt.Bytes32(), codeHash.Bytes())
protectedStorageAddr := fhevm_crypto.CreateProtectedStorageContractAddress(contractAddr)
_, _, leftOverGas, err = evm.CreateContract2(protectedStorageAddrCallerAddr, nil, common.Hash{}, gas, big.NewInt(0), protectedStorageAddr)
if err != nil {
ret = nil
contractAddr = common.Address{}
return
}
// TODO: consider reverting changes to `protectedStorageAddr` if actual contract creation fails.
return evm.CreateContract2(caller, code, codeHash, leftOverGas, endowment, contractAddr)
}

0 comments on commit a96f6e4

Please sign in to comment.