From 8165b6d48ab6f261db3d2ddfe54596d90fd8bc69 Mon Sep 17 00:00:00 2001 From: Petar Ivanov <29689712+dartdart26@users.noreply.github.com> Date: Tue, 11 Jun 2024 19:18:05 +0300 Subject: [PATCH] fix: add missing gas costs for loading ciphertexts --- fhevm/ciphertext_storage.go | 4 +- fhevm/contracts_test.go | 81 ------------------------------- fhevm/fhelib.go | 12 ++--- fhevm/operators_arithmetic_gas.go | 33 ++++++------- fhevm/operators_bit_gas.go | 23 ++++----- fhevm/operators_comparison.go | 16 +++--- fhevm/operators_comparison_gas.go | 56 ++++++++++----------- fhevm/operators_crypto_gas.go | 15 ++++-- fhevm/params.go | 56 ++++++++++----------- 9 files changed, 109 insertions(+), 187 deletions(-) diff --git a/fhevm/ciphertext_storage.go b/fhevm/ciphertext_storage.go index d9d1f3d..87888a7 100644 --- a/fhevm/ciphertext_storage.go +++ b/fhevm/ciphertext_storage.go @@ -75,7 +75,7 @@ func loadCiphertext(env EVMEnvironment, handle common.Hash) (ct *tfhe.TfheCipher metadataInt := newInt(env.GetState(ciphertextStorage, handle).Bytes()) if metadataInt.IsZero() { - return nil, 0 + return nil, ColdSloadCostEIP2929 } metadata := newCiphertextMetadata(metadataInt.Bytes32()) ctBytes := make([]byte, 0) @@ -93,7 +93,7 @@ func loadCiphertext(env EVMEnvironment, handle common.Hash) (ct *tfhe.TfheCipher err := ct.Deserialize(ctBytes, metadata.fheUintType) if err != nil { logger.Error("failed to deserialize ciphertext from storage", "err", err) - return nil, 0 + return nil, ColdSloadCostEIP2929 + DeserializeCiphertextGas } env.FhevmData().loadedCiphertexts[handle] = ct return ct, env.FhevmParams().GasCosts.FheStorageSloadGas[ct.Type()] diff --git a/fhevm/contracts_test.go b/fhevm/contracts_test.go index 7593d52..3915722 100644 --- a/fhevm/contracts_test.go +++ b/fhevm/contracts_test.go @@ -3474,23 +3474,6 @@ func FheArrayEqNoRhs(t *testing.T, fheUintType tfhe.FheUintType) { } } -func FheArrayEqNoRhsGas(t *testing.T, fheUintType tfhe.FheUintType) { - depth := 1 - environment := newTestEVMEnvironment() - environment.depth = depth - - lhs := make([]*big.Int, 3) - lhs[0] = loadCiphertextInTestMemory(environment, 1, depth, fheUintType).GetHash().Big() - lhs[1] = loadCiphertextInTestMemory(environment, 2, depth, fheUintType).GetHash().Big() - lhs[2] = loadCiphertextInTestMemory(environment, 3, depth, fheUintType).GetHash().Big() - input, _ := arrayEqMethod.Inputs.Pack(lhs) - - gas := fheArrayEqRequiredGas(environment, input) - if gas != 0 { - t.Fatalf("fheArrayEq expected 0 gas value") - } -} - func TestFheArrayEqUnverifiedCtInLhs(t *testing.T) { depth := 1 environment := newTestEVMEnvironment() @@ -3519,28 +3502,6 @@ func TestFheArrayEqUnverifiedCtInLhs(t *testing.T) { } } -func TestFheArrayEqUnverifiedCtInLhsGas(t *testing.T) { - depth := 1 - environment := newTestEVMEnvironment() - environment.depth = depth - - lhs := make([]*big.Int, 3) - lhs[0] = loadCiphertextInTestMemory(environment, 1, depth, tfhe.FheUint32).GetHash().Big() - lhs[0].Add(lhs[0], big.NewInt(1)) - lhs[1] = loadCiphertextInTestMemory(environment, 2, depth, tfhe.FheUint32).GetHash().Big() - lhs[2] = loadCiphertextInTestMemory(environment, 3, depth, tfhe.FheUint32).GetHash().Big() - rhs := make([]*big.Int, 3) - rhs[0] = loadCiphertextInTestMemory(environment, 1, depth, tfhe.FheUint32).GetHash().Big() - rhs[1] = loadCiphertextInTestMemory(environment, 2, depth, tfhe.FheUint32).GetHash().Big() - rhs[2] = loadCiphertextInTestMemory(environment, 3, depth, tfhe.FheUint32).GetHash().Big() - input, _ := arrayEqMethod.Inputs.Pack(lhs, rhs) - - gas := fheArrayEqRequiredGas(environment, input) - if gas != 0 { - t.Fatalf("fheArrayEq expected 0 gas value") - } -} - func TestFheArrayEqUnverifiedCtInRhs(t *testing.T) { depth := 1 environment := newTestEVMEnvironment() @@ -3570,28 +3531,6 @@ func TestFheArrayEqUnverifiedCtInRhs(t *testing.T) { } } -func TestFheArrayEqUnverifiedCtInRhsGas(t *testing.T) { - depth := 1 - environment := newTestEVMEnvironment() - environment.depth = depth - - lhs := make([]*big.Int, 3) - lhs[0] = loadCiphertextInTestMemory(environment, 1, depth, tfhe.FheUint32).GetHash().Big() - lhs[1] = loadCiphertextInTestMemory(environment, 2, depth, tfhe.FheUint32).GetHash().Big() - lhs[2] = loadCiphertextInTestMemory(environment, 3, depth, tfhe.FheUint32).GetHash().Big() - rhs := make([]*big.Int, 3) - rhs[0] = loadCiphertextInTestMemory(environment, 1, depth, tfhe.FheUint32).GetHash().Big() - rhs[1] = loadCiphertextInTestMemory(environment, 2, depth, tfhe.FheUint32).GetHash().Big() - rhs[1].Add(lhs[0], big.NewInt(1)) - rhs[2] = loadCiphertextInTestMemory(environment, 3, depth, tfhe.FheUint32).GetHash().Big() - input, _ := arrayEqMethod.Inputs.Pack(lhs, rhs) - - gas := fheArrayEqRequiredGas(environment, input) - if gas != 0 { - t.Fatalf("fheArrayEq expected 0 gas value") - } -} - func TestVerifyCiphertextInvalidType(t *testing.T) { depth := 1 environment := newTestEVMEnvironment() @@ -5164,23 +5103,3 @@ func TesFheArrayEqNoRhs32(t *testing.T) { func TestFheArrayEqNoRhs64(t *testing.T) { FheArrayEqNoRhs(t, tfhe.FheUint64) } - -func TestFheArrayEqNoRhsGas4(t *testing.T) { - FheArrayEqNoRhsGas(t, tfhe.FheUint4) -} - -func TestFheArrayEqNoRhsGas8(t *testing.T) { - FheArrayEqNoRhsGas(t, tfhe.FheUint8) -} - -func TestFheArrayEqNoRhsGas16(t *testing.T) { - FheArrayEqNoRhsGas(t, tfhe.FheUint16) -} - -func TesFheArrayEqNoRhsGas32(t *testing.T) { - FheArrayEqNoRhsGas(t, tfhe.FheUint32) -} - -func TestFheArrayEqNoRhsGas64(t *testing.T) { - FheArrayEqNoRhsGas(t, tfhe.FheUint64) -} diff --git a/fhevm/fhelib.go b/fhevm/fhelib.go index 5a32b91..029fc36 100644 --- a/fhevm/fhelib.go +++ b/fhevm/fhelib.go @@ -309,11 +309,11 @@ func load2Ciphertexts(environment EVMEnvironment, input []byte) (lhs *tfhe.TfheC loadGasRhs := uint64(0) lhs, loadGasLhs = loadCiphertext(environment, common.BytesToHash(input[0:32])) if lhs == nil { - return nil, nil, 0, errors.New("unverified ciphertext handle") + return nil, nil, loadGasLhs, errors.New("unverified ciphertext handle") } rhs, loadGasRhs = loadCiphertext(environment, common.BytesToHash(input[32:64])) if rhs == nil { - return nil, nil, 0, errors.New("unverified ciphertext handle") + return nil, nil, loadGasLhs + loadGasRhs, errors.New("unverified ciphertext handle") } err = nil loadGas = loadGasLhs + loadGasRhs @@ -337,15 +337,15 @@ func load3Ciphertexts(environment EVMEnvironment, input []byte) (first *tfhe.Tfh loadGasThird := uint64(0) first, loadGasFirst = loadCiphertext(environment, common.BytesToHash(input[0:32])) if first == nil { - return nil, nil, nil, 0, errors.New("unverified ciphertext handle") + return nil, nil, nil, loadGasFirst, errors.New("unverified ciphertext handle") } second, loadGasSecond = loadCiphertext(environment, common.BytesToHash(input[32:64])) if second == nil { - return nil, nil, nil, 0, errors.New("unverified ciphertext handle") + return nil, nil, nil, loadGasFirst + loadGasSecond, errors.New("unverified ciphertext handle") } third, loadGasThird = loadCiphertext(environment, common.BytesToHash(input[64:96])) if third == nil { - return nil, nil, nil, 0, errors.New("unverified ciphertext handle") + return nil, nil, nil, loadGasFirst + loadGasSecond + loadGasThird, errors.New("unverified ciphertext handle") } err = nil loadGas = loadGasFirst + loadGasSecond + loadGasThird @@ -358,7 +358,7 @@ func getScalarOperands(environment EVMEnvironment, input []byte) (lhs *tfhe.Tfhe } lhs, loadGas = loadCiphertext(environment, common.BytesToHash(input[0:32])) if lhs == nil { - return nil, nil, 0, errors.New("failed to load ciphertext") + return nil, nil, loadGas, errors.New("failed to load ciphertext") } rhs = &big.Int{} rhs.SetBytes(input[32:64]) diff --git a/fhevm/operators_arithmetic_gas.go b/fhevm/operators_arithmetic_gas.go index 4f0f8b4..ba462af 100644 --- a/fhevm/operators_arithmetic_gas.go +++ b/fhevm/operators_arithmetic_gas.go @@ -21,17 +21,17 @@ func fheAddSubRequiredGas(environment EVMEnvironment, input []byte) uint64 { lhs, rhs, loadGas, err = load2Ciphertexts(environment, input) if err != nil { logger.Error("fheAdd/Sub RequiredGas() ciphertext failed to load inputs", "err", err, "input", hex.EncodeToString(input)) - return 0 + return loadGas } if lhs.Type() != rhs.Type() { logger.Error("fheAdd/Sub RequiredGas() operand type mismatch", "lhs", lhs.Type(), "rhs", rhs.Type()) - return 0 + return loadGas } } else { lhs, _, loadGas, err = getScalarOperands(environment, input) if err != nil { logger.Error("fheAdd/Sub RequiredGas() scalar failed to load inputs", "err", err, "input", hex.EncodeToString(input)) - return 0 + return loadGas } } @@ -47,24 +47,22 @@ func fheMulRequiredGas(environment EVMEnvironment, input []byte) uint64 { logger.Error("fheMul RequiredGas() can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) return 0 } - loadGas := uint64(0) - var lhs, rhs *tfhe.TfheCiphertext if !isScalar { - lhs, rhs, loadGas, err = load2Ciphertexts(environment, input) + lhs, rhs, loadGas, err := load2Ciphertexts(environment, input) if err != nil { logger.Error("fheMul RequiredGas() ciphertext failed to load inputs", "err", err, "input", hex.EncodeToString(input)) - return 0 + return loadGas } if lhs.Type() != rhs.Type() { logger.Error("fheMul RequiredGas() operand type mismatch", "lhs", lhs.Type(), "rhs", rhs.Type()) - return 0 + return loadGas } - return environment.FhevmParams().GasCosts.FheMul[lhs.Type()] + return environment.FhevmParams().GasCosts.FheMul[lhs.Type()] + loadGas } else { - lhs, _, loadGas, err = getScalarOperands(environment, input) + lhs, _, loadGas, err := getScalarOperands(environment, input) if err != nil { logger.Error("fheMul RequiredGas() scalar failed to load inputs", "err", err, "input", hex.EncodeToString(input)) - return 0 + return loadGas } return environment.FhevmParams().GasCosts.FheScalarMul[lhs.Type()] + loadGas } @@ -79,16 +77,15 @@ func fheDivRequiredGas(environment EVMEnvironment, input []byte) uint64 { logger.Error("fheDiv RequiredGas() cannot detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) return 0 } - loadGas := uint64(0) - var lhs *tfhe.TfheCiphertext + if !isScalar { logger.Error("fheDiv RequiredGas() only scalar in division is supported, two ciphertexts received", "input", hex.EncodeToString(input)) return 0 } else { - lhs, _, loadGas, err = getScalarOperands(environment, input) + lhs, _, loadGas, err := getScalarOperands(environment, input) if err != nil { logger.Error("fheDiv RequiredGas() scalar failed to load inputs", "err", err, "input", hex.EncodeToString(input)) - return 0 + return loadGas } return environment.FhevmParams().GasCosts.FheScalarDiv[lhs.Type()] + loadGas } @@ -103,16 +100,14 @@ func fheRemRequiredGas(environment EVMEnvironment, input []byte) uint64 { logger.Error("fheRem RequiredGas() cannot detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) return 0 } - var lhs *tfhe.TfheCiphertext - loadGas := uint64(0) if !isScalar { logger.Error("fheRem RequiredGas() only scalar in division is supported, two ciphertexts received", "input", hex.EncodeToString(input)) return 0 } else { - lhs, _, loadGas, err = getScalarOperands(environment, input) + lhs, _, loadGas, err := getScalarOperands(environment, input) if err != nil { logger.Error("fheRem RequiredGas() scalar failed to load inputs", "err", err, "input", hex.EncodeToString(input)) - return 0 + return loadGas } return environment.FhevmParams().GasCosts.FheScalarRem[lhs.Type()] + loadGas } diff --git a/fhevm/operators_bit_gas.go b/fhevm/operators_bit_gas.go index d0dbb6c..b951c0a 100644 --- a/fhevm/operators_bit_gas.go +++ b/fhevm/operators_bit_gas.go @@ -4,7 +4,6 @@ import ( "encoding/hex" "github.com/ethereum/go-ethereum/common" - "github.com/zama-ai/fhevm-go/fhevm/tfhe" ) func fheShlRequiredGas(environment EVMEnvironment, input []byte) uint64 { @@ -16,24 +15,22 @@ func fheShlRequiredGas(environment EVMEnvironment, input []byte) uint64 { logger.Error("fheShift RequiredGas() can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) return 0 } - var lhs, rhs *tfhe.TfheCiphertext - loadGas := uint64(0) if !isScalar { - lhs, rhs, loadGas, err = load2Ciphertexts(environment, input) + lhs, rhs, loadGas, err := load2Ciphertexts(environment, input) if err != nil { logger.Error("fheShift RequiredGas() ciphertext failed to load inputs", "err", err, "input", hex.EncodeToString(input)) - return 0 + return loadGas } if lhs.Type() != rhs.Type() { logger.Error("fheShift RequiredGas() operand type mismatch", "lhs", lhs.Type(), "rhs", rhs.Type()) - return 0 + return loadGas } - return environment.FhevmParams().GasCosts.FheShift[lhs.Type()] + return environment.FhevmParams().GasCosts.FheShift[lhs.Type()] + loadGas } else { - lhs, _, loadGas, err = getScalarOperands(environment, input) + lhs, _, loadGas, err := getScalarOperands(environment, input) if err != nil { logger.Error("fheShift RequiredGas() scalar failed to load inputs", "err", err, "input", hex.EncodeToString(input)) - return 0 + return loadGas } return environment.FhevmParams().GasCosts.FheScalarShift[lhs.Type()] + loadGas } @@ -65,7 +62,7 @@ func fheNegRequiredGas(environment EVMEnvironment, input []byte) uint64 { ct, loadGas := loadCiphertext(environment, common.BytesToHash(input[0:32])) if ct == nil { logger.Error("fheNeg failed to load input", "input", hex.EncodeToString(input)) - return 0 + return loadGas } return environment.FhevmParams().GasCosts.FheNeg[ct.Type()] + loadGas } @@ -81,7 +78,7 @@ func fheNotRequiredGas(environment EVMEnvironment, input []byte) uint64 { ct, loadGas := loadCiphertext(environment, common.BytesToHash(input[0:32])) if ct == nil { logger.Error("fheNot failed to load input", "input", hex.EncodeToString(input)) - return 0 + return loadGas } return environment.FhevmParams().GasCosts.FheNot[ct.Type()] + loadGas } @@ -106,11 +103,11 @@ func fheBitAndRequiredGas(environment EVMEnvironment, input []byte) uint64 { lhs, rhs, loadGas, err := load2Ciphertexts(environment, input) if err != nil { logger.Error("Bitwise op RequiredGas() failed to load inputs", "err", err, "input", hex.EncodeToString(input)) - return 0 + return loadGas } if lhs.Type() != rhs.Type() { logger.Error("Bitwise op RequiredGas() operand type mismatch", "lhs", lhs.Type(), "rhs", rhs.Type()) - return 0 + return loadGas } return environment.FhevmParams().GasCosts.FheBitwiseOp[lhs.Type()] + loadGas } diff --git a/fhevm/operators_comparison.go b/fhevm/operators_comparison.go index 6739c17..aa59edb 100644 --- a/fhevm/operators_comparison.go +++ b/fhevm/operators_comparison.go @@ -617,20 +617,22 @@ func init() { } } -func getVerifiedCiphertexts(environment EVMEnvironment, unpacked interface{}) ([]*tfhe.TfheCiphertext, error) { +func getVerifiedCiphertexts(environment EVMEnvironment, unpacked interface{}) ([]*tfhe.TfheCiphertext, uint64, error) { + totalLoadGas := uint64(0) big, ok := unpacked.([]*big.Int) if !ok { - return nil, fmt.Errorf("fheArrayEq failed to cast to []*big.Int") + return nil, 0, fmt.Errorf("fheArrayEq failed to cast to []*big.Int") } ret := make([]*tfhe.TfheCiphertext, 0, len(big)) for _, b := range big { - ct, _ := loadCiphertext(environment, common.BigToHash(b)) + ct, loadGas := loadCiphertext(environment, common.BigToHash(b)) if ct == nil { - return nil, fmt.Errorf("fheArrayEq unverified ciphertext") + return nil, totalLoadGas + loadGas, fmt.Errorf("fheArrayEq unverified ciphertext") } + totalLoadGas += loadGas ret = append(ret, ct) } - return ret, nil + return ret, totalLoadGas, nil } func fheArrayEqRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool, runSpan trace.Span) ([]byte, error) { @@ -649,14 +651,14 @@ func fheArrayEqRun(environment EVMEnvironment, caller common.Address, addr commo return nil, err } - lhs, err := getVerifiedCiphertexts(environment, unpacked[0]) + lhs, _, err := getVerifiedCiphertexts(environment, unpacked[0]) if err != nil { msg := "fheArrayEqRun failed to get lhs to verified ciphertexts" logger.Error(msg, "err", err) return nil, err } - rhs, err := getVerifiedCiphertexts(environment, unpacked[1]) + rhs, _, err := getVerifiedCiphertexts(environment, unpacked[1]) if err != nil { msg := "fheArrayEqRun failed to get rhs to verified ciphertexts" logger.Error(msg, "err", err) diff --git a/fhevm/operators_comparison_gas.go b/fhevm/operators_comparison_gas.go index 4207cc2..86834b1 100644 --- a/fhevm/operators_comparison_gas.go +++ b/fhevm/operators_comparison_gas.go @@ -22,17 +22,17 @@ func fheLeRequiredGas(environment EVMEnvironment, input []byte) uint64 { lhs, rhs, loadGas, err = load2Ciphertexts(environment, input) if err != nil { logger.Error("comparison RequiredGas() failed to load input ciphertexts", "err", err, "input", hex.EncodeToString(input)) - return 0 + return loadGas } if lhs.Type() != rhs.Type() { logger.Error("comparison RequiredGas() operand type mismatch", "lhs", lhs.Type(), "rhs", rhs.Type()) - return 0 + return loadGas } } else { lhs, _, loadGas, err = getScalarOperands(environment, input) if err != nil { logger.Error("comparison RequiredGas() scalar failed to load input ciphertexts", "err", err, "input", hex.EncodeToString(input)) - return 0 + return loadGas } } return environment.FhevmParams().GasCosts.FheLe[lhs.Type()] + loadGas @@ -58,17 +58,17 @@ func fheEqRequiredGas(environment EVMEnvironment, input []byte) uint64 { lhs, rhs, loadGas, err = load2Ciphertexts(environment, input) if err != nil { logger.Error("comparison RequiredGas() failed to load input ciphertexts", "err", err, "input", hex.EncodeToString(input)) - return 0 + return loadGas } if lhs.Type() != rhs.Type() { logger.Error("comparison RequiredGas() operand type mismatch", "lhs", lhs.Type(), "rhs", rhs.Type()) - return 0 + return loadGas } } else { lhs, _, loadGas, err = getScalarOperands(environment, input) if err != nil { logger.Error("comparison RequiredGas() scalar failed to load input ciphertexts", "err", err, "input", hex.EncodeToString(input)) - return 0 + return loadGas } } return environment.FhevmParams().GasCosts.FheEq[lhs.Type()] + loadGas @@ -98,10 +98,8 @@ func fheMinRequiredGas(environment EVMEnvironment, input []byte) uint64 { logger.Error("fheMin/Max RequiredGas() can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) return 0 } - var lhs, rhs *tfhe.TfheCiphertext - loadGas := uint64(0) if !isScalar { - lhs, rhs, loadGas, err = load2Ciphertexts(environment, input) + lhs, rhs, loadGas, err := load2Ciphertexts(environment, input) if err != nil { logger.Error("fheMin/Max RequiredGas() failed to load input ciphertexts", "err", err, "input", hex.EncodeToString(input)) return 0 @@ -110,9 +108,9 @@ func fheMinRequiredGas(environment EVMEnvironment, input []byte) uint64 { logger.Error("fheMin/Max RequiredGas() operand type mismatch", "lhs", lhs.Type(), "rhs", rhs.Type()) return 0 } - return environment.FhevmParams().GasCosts.FheMinMax[lhs.Type()] + return environment.FhevmParams().GasCosts.FheMinMax[lhs.Type()] + loadGas } else { - lhs, _, loadGas, err = getScalarOperands(environment, input) + lhs, _, loadGas, err := getScalarOperands(environment, input) if err != nil { logger.Error("fheMin/Max RequiredGas() scalar failed to load input ciphertexts", "err", err, "input", hex.EncodeToString(input)) return 0 @@ -133,15 +131,15 @@ func fheIfThenElseRequiredGas(environment EVMEnvironment, input []byte) uint64 { first, second, third, loadGas, err := load3Ciphertexts(environment, input) if err != nil { logger.Error("IfThenElse op RequiredGas()failed to load input ciphertexts", "err", err, "input", hex.EncodeToString(input)) - return 0 + return loadGas } if first.Type() != tfhe.FheBool { logger.Error("IfThenElse op RequiredGas() invalid type for condition", "first", first.Type()) - return 0 + return loadGas } if second.Type() != third.Type() { logger.Error("IfThenElse op RequiredGas() operand type mismatch", "second", second.Type(), "third", third.Type()) - return 0 + return loadGas } return environment.FhevmParams().GasCosts.FheIfThenElse[second.Type()] + loadGas } @@ -162,50 +160,52 @@ func fheArrayEqRequiredGas(environment EVMEnvironment, input []byte) uint64 { return 0 } - lhs, err := getVerifiedCiphertexts(environment, unpacked[0]) + lhs, lhsLoadGas, err := getVerifiedCiphertexts(environment, unpacked[0]) if err != nil { msg := "fheArrayEqRun RequiredGas() failed to get lhs to verified ciphertexts" logger.Error(msg, "err", err) - return 0 + return lhsLoadGas } - rhs, err := getVerifiedCiphertexts(environment, unpacked[1]) + rhs, rhsLoadGas, err := getVerifiedCiphertexts(environment, unpacked[1]) if err != nil { msg := "fheArrayEqRun RequiredGas() failed to get rhs to verified ciphertexts" logger.Error(msg, "err", err) - return 0 + return lhsLoadGas + rhsLoadGas } + totalLoadGas := lhsLoadGas + rhsLoadGas + if len(lhs) != len(rhs) || (len(lhs) == 0 && len(rhs) == 0) { - return environment.FhevmParams().GasCosts.FheTrivialEncrypt[tfhe.FheBool] + return environment.FhevmParams().GasCosts.FheTrivialEncrypt[tfhe.FheBool] + totalLoadGas } numElements := len(lhs) elementType := lhs[0].Type() // TODO: tie to supported types in tfhe.TfheCiphertext.EqArray() if elementType != tfhe.FheUint4 && elementType != tfhe.FheUint8 && elementType != tfhe.FheUint16 && elementType != tfhe.FheUint32 && elementType != tfhe.FheUint64 { - return 0 + return totalLoadGas } for i := range lhs { if lhs[i].Type() != elementType || rhs[i].Type() != elementType { - return 0 + return totalLoadGas } } numBits := elementType.NumBits() * uint(numElements) if numBits <= 4 { - return environment.FhevmParams().GasCosts.FheEq[tfhe.FheUint4] + return environment.FhevmParams().GasCosts.FheEq[tfhe.FheUint4] + totalLoadGas } else if numBits <= 8 { - return environment.FhevmParams().GasCosts.FheEq[tfhe.FheUint8] + return environment.FhevmParams().GasCosts.FheEq[tfhe.FheUint8] + totalLoadGas } else if numBits <= 16 { - return environment.FhevmParams().GasCosts.FheEq[tfhe.FheUint16] + return environment.FhevmParams().GasCosts.FheEq[tfhe.FheUint16] + totalLoadGas } else if numBits <= 32 { - return environment.FhevmParams().GasCosts.FheEq[tfhe.FheUint32] + return environment.FhevmParams().GasCosts.FheEq[tfhe.FheUint32] + totalLoadGas } else if numBits <= 64 { - return environment.FhevmParams().GasCosts.FheEq[tfhe.FheUint64] + return environment.FhevmParams().GasCosts.FheEq[tfhe.FheUint64] + totalLoadGas } else if numBits <= 160 { - return environment.FhevmParams().GasCosts.FheEq[tfhe.FheUint160] + return environment.FhevmParams().GasCosts.FheEq[tfhe.FheUint160] + totalLoadGas } else { - return (environment.FhevmParams().GasCosts.FheEq[tfhe.FheUint160] + environment.FhevmParams().GasCosts.FheArrayEqBigArrayFactor) * (uint64(numBits) / 160) + return ((environment.FhevmParams().GasCosts.FheEq[tfhe.FheUint160] + environment.FhevmParams().GasCosts.FheArrayEqBigArrayFactor) * (uint64(numBits) / 160)) + totalLoadGas } } diff --git a/fhevm/operators_crypto_gas.go b/fhevm/operators_crypto_gas.go index 5900a17..ec45e63 100644 --- a/fhevm/operators_crypto_gas.go +++ b/fhevm/operators_crypto_gas.go @@ -29,7 +29,7 @@ func reencryptRequiredGas(environment EVMEnvironment, input []byte) uint64 { ct, loadGas := loadCiphertext(environment, 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 + return loadGas } return environment.FhevmParams().GasCosts.FheReencrypt[ct.Type()] + loadGas } @@ -55,13 +55,20 @@ func getCiphertextRequiredGas(environment EVMEnvironment, input []byte) uint64 { func castRequiredGas(environment EVMEnvironment, input []byte) uint64 { input = input[:minInt(33, len(input))] + logger := environment.GetLogger() if len(input) != 33 { - environment.GetLogger().Error( + logger.Error( "cast RequiredGas() input needs to contain a ciphertext and one byte for its type", "len", len(input)) return 0 } - return environment.FhevmParams().GasCosts.FheCast + + ct, loadGas := loadCiphertext(environment, common.BytesToHash(input[0:32])) + if ct == nil { + logger.Error("cast RequiredGas() input doesn't point to verified ciphertext", "input", hex.EncodeToString(input)) + return loadGas + } + return environment.FhevmParams().GasCosts.FheCast + loadGas } func decryptRequiredGas(environment EVMEnvironment, input []byte) uint64 { @@ -75,7 +82,7 @@ func decryptRequiredGas(environment EVMEnvironment, input []byte) uint64 { ct, loadGas := loadCiphertext(environment, common.BytesToHash(input)) if ct == nil { logger.Error("decrypt RequiredGas() input doesn't point to verified ciphertext", "input", hex.EncodeToString(input)) - return 0 + return loadGas } return environment.FhevmParams().GasCosts.FheDecrypt[ct.Type()] + loadGas } diff --git a/fhevm/params.go b/fhevm/params.go index eccf96c..3ba5588 100644 --- a/fhevm/params.go +++ b/fhevm/params.go @@ -11,7 +11,9 @@ const EvmNetSstoreInitGas uint64 = 20000 const AdjustFHEGas uint64 = 10000 const ColdSloadCostEIP2929 uint64 = 2100 -const GetNonExistentCiphertextGas uint64 = 1000 +const GetNonExistentCiphertextGas uint64 = ColdSloadCostEIP2929 + +const DeserializeCiphertextGas uint64 = 30 // Base costs of fhEVM SSTORE and SLOAD operations. // TODO: We don't take whether the slot is cold or warm into consideration. @@ -31,32 +33,32 @@ type FhevmParams struct { } type GasCosts struct { - FheCast uint64 - FhePubKey uint64 - FheAddSub map[tfhe.FheUintType]uint64 - FheDecrypt map[tfhe.FheUintType]uint64 - FheBitwiseOp map[tfhe.FheUintType]uint64 - FheMul map[tfhe.FheUintType]uint64 - FheScalarMul map[tfhe.FheUintType]uint64 - FheScalarDiv map[tfhe.FheUintType]uint64 - FheScalarRem map[tfhe.FheUintType]uint64 - FheShift map[tfhe.FheUintType]uint64 - FheScalarShift map[tfhe.FheUintType]uint64 - FheEq map[tfhe.FheUintType]uint64 - FheArrayEqBigArrayFactor uint64 // TODO: either rename or come up with a better solution - FheLe map[tfhe.FheUintType]uint64 - FheMinMax map[tfhe.FheUintType]uint64 - FheScalarMinMax map[tfhe.FheUintType]uint64 - FheNot map[tfhe.FheUintType]uint64 - FheNeg map[tfhe.FheUintType]uint64 - FheReencrypt map[tfhe.FheUintType]uint64 - FheTrivialEncrypt map[tfhe.FheUintType]uint64 - FheRand map[tfhe.FheUintType]uint64 - FheIfThenElse map[tfhe.FheUintType]uint64 - FheVerify map[tfhe.FheUintType]uint64 - FheGetCiphertext map[tfhe.FheUintType]uint64 - FheStorageSstoreGas map[tfhe.FheUintType]uint64 - FheStorageSloadGas map[tfhe.FheUintType]uint64 + FheCast uint64 + FhePubKey uint64 + FheAddSub map[tfhe.FheUintType]uint64 + FheDecrypt map[tfhe.FheUintType]uint64 + FheBitwiseOp map[tfhe.FheUintType]uint64 + FheMul map[tfhe.FheUintType]uint64 + FheScalarMul map[tfhe.FheUintType]uint64 + FheScalarDiv map[tfhe.FheUintType]uint64 + FheScalarRem map[tfhe.FheUintType]uint64 + FheShift map[tfhe.FheUintType]uint64 + FheScalarShift map[tfhe.FheUintType]uint64 + FheEq map[tfhe.FheUintType]uint64 + FheArrayEqBigArrayFactor uint64 // TODO: either rename or come up with a better solution + FheLe map[tfhe.FheUintType]uint64 + FheMinMax map[tfhe.FheUintType]uint64 + FheScalarMinMax map[tfhe.FheUintType]uint64 + FheNot map[tfhe.FheUintType]uint64 + FheNeg map[tfhe.FheUintType]uint64 + FheReencrypt map[tfhe.FheUintType]uint64 + FheTrivialEncrypt map[tfhe.FheUintType]uint64 + FheRand map[tfhe.FheUintType]uint64 + FheIfThenElse map[tfhe.FheUintType]uint64 + FheVerify map[tfhe.FheUintType]uint64 + FheGetCiphertext map[tfhe.FheUintType]uint64 + FheStorageSstoreGas map[tfhe.FheUintType]uint64 + FheStorageSloadGas map[tfhe.FheUintType]uint64 } func DefaultGasCosts() GasCosts {