From a96f6e49c8dba82a82b619ddf623e9b5e4202e72 Mon Sep 17 00:00:00 2001 From: Petar Ivanov <29689712+dartdart26@users.noreply.github.com> Date: Wed, 14 Aug 2024 12:34:36 +0300 Subject: [PATCH] docs: update Integration guide and FheLib example --- docs/getting_started/FheLib.md | 25 ++++++--------------- docs/getting_started/Integration.md | 34 ++++++++++++++++++++++++++++- fhevm/evm.go | 29 ------------------------ 3 files changed, 40 insertions(+), 48 deletions(-) diff --git a/docs/getting_started/FheLib.md b/docs/getting_started/FheLib.md index c566824..101af53 100644 --- a/docs/getting_started/FheLib.md +++ b/docs/getting_started/FheLib.md @@ -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. @@ -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" ], @@ -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:]) -``` \ No newline at end of file +``` diff --git a/docs/getting_started/Integration.md b/docs/getting_started/Integration.md index 9cb3992..c655820 100644 --- a/docs/getting_started/Integration.md +++ b/docs/getting_started/Integration.md @@ -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 @@ -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`: diff --git a/fhevm/evm.go b/fhevm/evm.go index 5878128..3ddc58e 100644 --- a/fhevm/evm.go +++ b/fhevm/evm.go @@ -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" ) @@ -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) -}