Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

doc: update Integration guide and FheLib example #129

Merged
merged 1 commit into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
}
Loading