Skip to content

Commit

Permalink
Merge pull request ethereum#110 from zama-ai/petar/pub-key-precompile
Browse files Browse the repository at this point in the history
Add the fhePubKey precompile
  • Loading branch information
dartdart26 authored Jun 19, 2023
2 parents 1bdc776 + 4a56618 commit 0f50420
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 19 deletions.
28 changes: 22 additions & 6 deletions core/vm/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ var PrecompiledContractsHomestead = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{65}): &fheAdd{},
common.BytesToAddress([]byte{66}): &verifyCiphertext{},
common.BytesToAddress([]byte{67}): &reencrypt{},
// slot 68 is available for use
common.BytesToAddress([]byte{68}): &fhePubKey{},
common.BytesToAddress([]byte{69}): &require{},
common.BytesToAddress([]byte{70}): &fheLte{},
common.BytesToAddress([]byte{71}): &fheSub{},
Expand Down Expand Up @@ -97,7 +97,7 @@ var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{65}): &fheAdd{},
common.BytesToAddress([]byte{66}): &verifyCiphertext{},
common.BytesToAddress([]byte{67}): &reencrypt{},
// slot 68 is available for use
common.BytesToAddress([]byte{68}): &fhePubKey{},
common.BytesToAddress([]byte{69}): &require{},
common.BytesToAddress([]byte{70}): &fheLte{},
common.BytesToAddress([]byte{71}): &fheSub{},
Expand Down Expand Up @@ -126,7 +126,7 @@ var PrecompiledContractsIstanbul = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{65}): &fheAdd{},
common.BytesToAddress([]byte{66}): &verifyCiphertext{},
common.BytesToAddress([]byte{67}): &reencrypt{},
// slot 68 is available for use
common.BytesToAddress([]byte{68}): &fhePubKey{},
common.BytesToAddress([]byte{69}): &require{},
common.BytesToAddress([]byte{70}): &fheLte{},
common.BytesToAddress([]byte{71}): &fheSub{},
Expand Down Expand Up @@ -155,7 +155,7 @@ var PrecompiledContractsBerlin = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{65}): &fheAdd{},
common.BytesToAddress([]byte{66}): &verifyCiphertext{},
common.BytesToAddress([]byte{67}): &reencrypt{},
// slot 68 is available for use
common.BytesToAddress([]byte{68}): &fhePubKey{},
common.BytesToAddress([]byte{69}): &require{},
common.BytesToAddress([]byte{70}): &fheLte{},
common.BytesToAddress([]byte{71}): &fheSub{},
Expand Down Expand Up @@ -184,7 +184,7 @@ var PrecompiledContractsBLS = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{65}): &fheAdd{},
common.BytesToAddress([]byte{66}): &verifyCiphertext{},
common.BytesToAddress([]byte{67}): &reencrypt{},
// slot 68 is available for use
common.BytesToAddress([]byte{68}): &fhePubKey{},
common.BytesToAddress([]byte{69}): &require{},
common.BytesToAddress([]byte{70}): &fheLte{},
common.BytesToAddress([]byte{71}): &fheSub{},
Expand Down Expand Up @@ -1474,7 +1474,7 @@ func (e *reencrypt) RequiredGas(accessibleState PrecompileAccessibleState, input
logger.Error("reencrypt RequiredGas() input len must be 64 bytes", "input", hex.EncodeToString(input), "len", len(input))
return 0
}
ct := getVerifiedCiphertext(accessibleState, common.BytesToHash(input))
ct := getVerifiedCiphertext(accessibleState, common.BytesToHash(input[0:32]))
if ct == nil {
logger.Error("reencrypt RequiredGas() input doesn't point to verified ciphertext", "input", hex.EncodeToString(input))
return 0
Expand Down Expand Up @@ -2039,3 +2039,19 @@ func (e *faucet) Run(accessibleState PrecompileAccessibleState, caller common.Ad
accessibleState.Interpreter().evm.StateDB.AddBalance(common.BytesToAddress(input[0:20]), big.NewInt(1000000000000000000))
return input, nil
}

type fhePubKey struct{}

func (e *fhePubKey) RequiredGas(accessibleState PrecompileAccessibleState, input []byte) uint64 {
return params.FhePubKeyGas
}

func (e *fhePubKey) Run(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) {
existing := accessibleState.Interpreter().evm.StateDB.GetState(fhePubKeyHashPrecompile, fhePubKeyHashSlot)
if existing != pksHash {
msg := "fhePubKey FHE public key hash doesn't match one stored in state"
accessibleState.Interpreter().evm.Logger.Error(msg, "existing", existing.Hex(), "pksHash", pksHash.Hex())
return nil, errors.New(msg)
}
return toEVMBytes(pksBytes), nil
}
16 changes: 16 additions & 0 deletions core/vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,16 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
return ret, address, contract.Gas, err
}

var fhePubKeyHashPrecompile = common.BytesToAddress([]byte{68})
var fhePubKeyHashSlot = common.Hash{}

func (evm *EVM) persistFhePubKeyHash() {
existing := evm.StateDB.GetState(fhePubKeyHashPrecompile, fhePubKeyHashSlot)
if newInt(existing[:]).IsZero() {
evm.StateDB.SetState(fhePubKeyHashPrecompile, fhePubKeyHashSlot, pksHash)
}
}

// 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) {
nonce := evm.StateDB.GetNonce(caller.Address())
Expand All @@ -549,6 +559,9 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
// Return the actual contract's return value and contract address.
protectedStorageContractAddr := crypto.CreateProtectedStorageContractAddress(contractAddr)
_, _, leftOverGas, err = evm.create(caller, &codeAndHash{}, leftOverGas, big.NewInt(0), protectedStorageContractAddr, CREATE)
if err == nil {
evm.persistFhePubKeyHash()
}
return
}

Expand All @@ -571,6 +584,9 @@ func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *
// Return the actual contract's return value and contract address.
protectedStorageContractAddr := crypto.CreateProtectedStorageContractAddress(contractAddr)
_, _, leftOverGas, err = evm.create(caller, &codeAndHash{}, gas, endowment, protectedStorageContractAddr, CREATE2)
if err == nil {
evm.persistFhePubKeyHash()
}
return
}

Expand Down
12 changes: 6 additions & 6 deletions core/vm/operations_acl.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@ import (
)

var gasProtectedStorageSstore = map[fheUintType]uint64{
FheUint8: params.FheUint8ProtectedStorageSstore,
FheUint16: params.FheUint16ProtectedStorageSstore,
FheUint32: params.FheUint32ProtectedStorageSstore,
FheUint8: params.FheUint8ProtectedStorageSstoreGas,
FheUint16: params.FheUint16ProtectedStorageSstoreGas,
FheUint32: params.FheUint32ProtectedStorageSstoreGas,
}

var gasProtectedStorageSload = map[fheUintType]uint64{
FheUint8: params.FheUint8ProtectedStorageSload,
FheUint16: params.FheUint16ProtectedStorageSload,
FheUint32: params.FheUint32ProtectedStorageSload,
FheUint8: params.FheUint8ProtectedStorageSloadGas,
FheUint16: params.FheUint16ProtectedStorageSloadGas,
FheUint32: params.FheUint32ProtectedStorageSloadGas,
}

func makeGasSStoreFunc(clearingRefund uint64) gasFunc {
Expand Down
6 changes: 5 additions & 1 deletion core/vm/tfhe.go
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,8 @@ var expandedFheCiphertextSize map[fheUintType]uint
var sks unsafe.Pointer
var cks unsafe.Pointer
var pks unsafe.Pointer
var pksBytes []byte
var pksHash common.Hash
var networkKeysDir string
var usersKeysDir string

Expand Down Expand Up @@ -562,11 +564,13 @@ func init() {
}
cks = C.deserialize_client_key(toBufferView(cksBytes))

pksBytes, err := os.ReadFile(networkKeysDir + "pks")
pksBytes, err = os.ReadFile(networkKeysDir + "pks")
if err != nil {
pksBytes = nil
fmt.Println("WARNING: file pks not found.")
return
}
pksHash = crypto.Keccak256Hash(pksBytes)
pks = C.deserialize_compact_public_key(toBufferView(pksBytes))
}

Expand Down
14 changes: 8 additions & 6 deletions params/protocol_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,14 +197,16 @@ const (
// TODO: The values here are chosen somewhat arbitrarily (at least the 8 bit ones). Also, we don't
// take into account whether a ciphertext existed (either "current" or "original") for the given handle.
// Finally, costs are likely to change in the future.
FheUint8ProtectedStorageSstore uint64 = NetSstoreInitGas * 3
FheUint16ProtectedStorageSstore uint64 = FheUint8ProtectedStorageSstore * 2
FheUint32ProtectedStorageSstore uint64 = FheUint16ProtectedStorageSstore * 4
FheUint8ProtectedStorageSstoreGas uint64 = NetSstoreInitGas * 3
FheUint16ProtectedStorageSstoreGas uint64 = FheUint8ProtectedStorageSstoreGas * 2
FheUint32ProtectedStorageSstoreGas uint64 = FheUint16ProtectedStorageSstoreGas * 4

// TODO: We don't take whether the slot is cold or warm into consideration.
FheUint8ProtectedStorageSload uint64 = ColdSloadCostEIP2929 * 3
FheUint16ProtectedStorageSload uint64 = FheUint8ProtectedStorageSload * 2
FheUint32ProtectedStorageSload uint64 = FheUint16ProtectedStorageSload * 4
FheUint8ProtectedStorageSloadGas uint64 = ColdSloadCostEIP2929 * 3
FheUint16ProtectedStorageSloadGas uint64 = FheUint8ProtectedStorageSloadGas * 2
FheUint32ProtectedStorageSloadGas uint64 = FheUint16ProtectedStorageSloadGas * 4

FhePubKeyGas uint64 = 2
)

// Gas discount table for BLS12-381 G1 and G2 multi exponentiation operations
Expand Down

0 comments on commit 0f50420

Please sign in to comment.