From 5604f781bc0758bf1fef027b59036c5047fa35f8 Mon Sep 17 00:00:00 2001 From: youben11 Date: Wed, 14 Feb 2024 10:41:25 +0100 Subject: [PATCH] refactor: clean and separate the fhelib --- fhevm/contracts_test.go | 364 ++--- fhevm/evm.go | 110 +- fhevm/fhelib.go | 318 +++++ fhevm/fhelib_required_gas.go | 476 +++++++ fhevm/fhelib_run.go | 1731 ++++++++++++++++++++++++ fhevm/instructions.go | 12 +- fhevm/instructions_test.go | 26 +- fhevm/interface.go | 14 +- fhevm/interpreter.go | 21 +- fhevm/precompiles.go | 2483 +--------------------------------- fhevm/tfhe_ciphertext.go | 125 +- fhevm/tfhe_key_management.go | 23 +- fhevm/tfhe_test.go | 448 +++--- fhevm/tfhe_wrappers.go | 15 +- 14 files changed, 3101 insertions(+), 3065 deletions(-) create mode 100644 fhevm/fhelib.go create mode 100644 fhevm/fhelib_required_gas.go create mode 100644 fhevm/fhelib_run.go diff --git a/fhevm/contracts_test.go b/fhevm/contracts_test.go index 1d61c64..6450a13 100644 --- a/fhevm/contracts_test.go +++ b/fhevm/contracts_test.go @@ -2,6 +2,7 @@ package fhevm import ( "bytes" + "encoding/binary" "encoding/hex" "errors" "math/big" @@ -63,18 +64,18 @@ func toPrecompileInputNoScalar(isScalar bool, hashes ...common.Hash) []byte { func evaluateRemainingOptimisticRequiresWithoutKms(environment EVMEnvironment) (bool, error) { requires := environment.FhevmData().optimisticRequires len := len(requires) - defer func() { environment.FhevmData().optimisticRequires = make([]*tfheCiphertext, 0) }() + defer func() { environment.FhevmData().resetOptimisticRequires() }() if len != 0 { - var cumulative *tfheCiphertext = requires[0] + var cumulative *TfheCiphertext = requires[0] var err error for i := 1; i < len; i++ { - cumulative, err = cumulative.bitand(requires[i]) + cumulative, err = cumulative.Bitand(requires[i]) if err != nil { environment.GetLogger().Error("evaluateRemainingOptimisticRequires bitand failed", "err", err) return false, err } } - result, err := cumulative.decrypt() + result, err := cumulative.Decrypt() return result.Uint64() != 0, err } return true, nil @@ -113,7 +114,7 @@ func decryptRunWithoutKms(environment EVMEnvironment, caller common.Address, add return nil, ErrExecutionReverted } - plaintext, err := ct.ciphertext.decrypt() + plaintext, err := ct.ciphertext.Decrypt() if err != nil { logger.Error("decrypt failed", "err", err) return nil, err @@ -159,6 +160,14 @@ func toLibPrecompileInputNoScalar(method string, hashes ...common.Hash) []byte { return ret } +// verifyCiphertext expect a certain format: mainly some padding and the size of the buffer +func prepareInputForVerifyCiphertext(input []byte) []byte { + padding := make([]byte, 60) + size := make([]byte, 4) + binary.BigEndian.PutUint32(size, uint32(len(input))) + return append(append(padding, size...), input...) +} + func VerifyCiphertext(t *testing.T, fheUintType FheUintType) { var value uint64 switch fheUintType { @@ -177,19 +186,19 @@ func VerifyCiphertext(t *testing.T, fheUintType FheUintType) { addr := common.Address{} readOnly := false compact := encryptAndSerializeCompact(value, fheUintType) - input := append(compact, byte(fheUintType)) + input := prepareInputForVerifyCiphertext(append(compact, byte(fheUintType))) out, err := verifyCiphertextRun(environment, addr, addr, input, readOnly) if err != nil { t.Fatalf(err.Error()) } - ct := new(tfheCiphertext) - if err = ct.deserializeCompact(compact, fheUintType); err != nil { + ct := new(TfheCiphertext) + if err = ct.DeserializeCompact(compact, fheUintType); err != nil { t.Fatalf(err.Error()) } - if common.BytesToHash(out) != ct.getHash() { + if common.BytesToHash(out) != ct.GetHash() { t.Fatalf("output hash in verifyCipertext is incorrect") } - res := getVerifiedCiphertextFromEVM(environment, ct.getHash()) + res := getVerifiedCiphertextFromEVM(environment, ct.GetHash()) if res == nil { t.Fatalf("verifyCiphertext must have verified given ciphertext") } @@ -213,7 +222,7 @@ func VerifyCiphertextBadType(t *testing.T, actualType FheUintType, metadataType addr := common.Address{} readOnly := false compact := encryptAndSerializeCompact(value, actualType) - input := append(compact, byte(metadataType)) + input := prepareInputForVerifyCiphertext(append(compact, byte(metadataType))) _, err := verifyCiphertextRun(environment, addr, addr, input, readOnly) if err == nil { t.Fatalf("verifyCiphertext must have failed on type mismatch") @@ -246,11 +255,11 @@ func TrivialEncrypt(t *testing.T, fheUintType FheUintType) { if err != nil { t.Fatalf(err.Error()) } - ct := new(tfheCiphertext).trivialEncrypt(value, fheUintType) - if common.BytesToHash(out) != ct.getHash() { + ct := new(TfheCiphertext).TrivialEncrypt(value, fheUintType) + if common.BytesToHash(out) != ct.GetHash() { t.Fatalf("output hash in verifyCipertext is incorrect") } - res := getVerifiedCiphertextFromEVM(environment, ct.getHash()) + res := getVerifiedCiphertextFromEVM(environment, ct.GetHash()) if res == nil { t.Fatalf("verifyCiphertext must have verified given ciphertext") } @@ -280,12 +289,12 @@ func FheLibAdd(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } input := toLibPrecompileInput(signature, scalar, lhsHash, rhsHash) out, err := FheLibRun(environment, addr, addr, input, readOnly) @@ -296,7 +305,7 @@ func FheLibAdd(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != expected { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), expected) } @@ -325,12 +334,12 @@ func FheLibSub(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } input := toLibPrecompileInput(signature, scalar, lhsHash, rhsHash) out, err := FheLibRun(environment, addr, addr, input, readOnly) @@ -341,7 +350,7 @@ func FheLibSub(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != expected { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), expected) } @@ -370,12 +379,12 @@ func FheLibMul(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } input := toLibPrecompileInput(signature, scalar, lhsHash, rhsHash) out, err := FheLibRun(environment, addr, addr, input, readOnly) @@ -386,7 +395,7 @@ func FheLibMul(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != expected { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), expected) } @@ -414,12 +423,12 @@ func FheLibLe(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } // lhs <= rhs @@ -432,7 +441,7 @@ func FheLibLe(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != 0 { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), 0) } @@ -450,7 +459,7 @@ func FheLibLe(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err = res.ciphertext.decrypt() + decrypted, err = res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != 1 { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), 1) } @@ -480,12 +489,12 @@ func FheLibLt(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } // lhs < rhs @@ -498,7 +507,7 @@ func FheLibLt(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != 0 { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), 0) } @@ -516,7 +525,7 @@ func FheLibLt(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err = res.ciphertext.decrypt() + decrypted, err = res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != 1 { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), 1) } @@ -545,12 +554,12 @@ func FheLibEq(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } // lhs == rhs input1 := toLibPrecompileInput(signature, scalar, lhsHash, rhsHash) @@ -562,7 +571,7 @@ func FheLibEq(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != 0 { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), 0) } @@ -590,12 +599,12 @@ func FheLibGe(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } // lhs >= rhs input1 := toLibPrecompileInput(signature, scalar, lhsHash, rhsHash) @@ -607,7 +616,7 @@ func FheLibGe(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != 1 { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), 1) } @@ -624,7 +633,7 @@ func FheLibGe(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err = res.ciphertext.decrypt() + decrypted, err = res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != 0 { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), 0) } @@ -654,12 +663,12 @@ func FheLibGt(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } // lhs > rhs input1 := toLibPrecompileInput(signature, scalar, lhsHash, rhsHash) @@ -671,7 +680,7 @@ func FheLibGt(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != 1 { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), 1) } @@ -689,7 +698,7 @@ func FheLibGt(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err = res.ciphertext.decrypt() + decrypted, err = res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != 0 { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), 0) } @@ -719,12 +728,12 @@ func FheLibShl(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } input := toLibPrecompileInput(signature, scalar, lhsHash, rhsHash) out, err := FheLibRun(environment, addr, addr, input, readOnly) @@ -735,7 +744,7 @@ func FheLibShl(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != expected { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), expected) } @@ -764,12 +773,12 @@ func FheLibShr(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } input := toLibPrecompileInput(signature, scalar, lhsHash, rhsHash) out, err := FheLibRun(environment, addr, addr, input, readOnly) @@ -780,7 +789,7 @@ func FheLibShr(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != expected { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), expected) } @@ -808,12 +817,12 @@ func FheLibNe(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } // lhs == rhs input1 := toLibPrecompileInput(signature, scalar, lhsHash, rhsHash) @@ -825,7 +834,7 @@ func FheLibNe(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != 1 { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), 1) } @@ -854,12 +863,12 @@ func FheLibMin(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } input := toLibPrecompileInput(signature, scalar, lhsHash, rhsHash) @@ -871,7 +880,7 @@ func FheLibMin(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != rhs { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), rhs) } @@ -888,7 +897,7 @@ func FheLibMin(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err = res.ciphertext.decrypt() + decrypted, err = res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != rhs { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), rhs) } @@ -918,12 +927,12 @@ func FheLibMax(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } input := toLibPrecompileInput(signature, scalar, lhsHash, rhsHash) @@ -935,7 +944,7 @@ func FheLibMax(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != lhs { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), lhs) } @@ -952,7 +961,7 @@ func FheLibMax(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err = res.ciphertext.decrypt() + decrypted, err = res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != lhs { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), lhs) } @@ -982,7 +991,7 @@ func FheLibNeg(t *testing.T, fheUintType FheUintType) { environment.depth = depth addr := common.Address{} readOnly := false - ptHash := verifyCiphertextInTestMemory(environment, pt, depth, fheUintType).getHash() + ptHash := verifyCiphertextInTestMemory(environment, pt, depth, fheUintType).GetHash() input := toLibPrecompileInputNoScalar(signature, ptHash) out, err := FheLibRun(environment, addr, addr, input, readOnly) @@ -993,7 +1002,7 @@ func FheLibNeg(t *testing.T, fheUintType FheUintType) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != expected { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), expected) } @@ -1022,7 +1031,7 @@ func FheLibNot(t *testing.T, fheUintType FheUintType) { environment.depth = depth addr := common.Address{} readOnly := false - ptHash := verifyCiphertextInTestMemory(environment, pt, depth, fheUintType).getHash() + ptHash := verifyCiphertextInTestMemory(environment, pt, depth, fheUintType).GetHash() input := toLibPrecompileInputNoScalar(signature, ptHash) out, err := FheLibRun(environment, addr, addr, input, readOnly) @@ -1033,7 +1042,7 @@ func FheLibNot(t *testing.T, fheUintType FheUintType) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != expected { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), expected) } @@ -1063,12 +1072,12 @@ func FheLibDiv(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } input := toLibPrecompileInput(signature, scalar, lhsHash, rhsHash) out, err := FheLibRun(environment, addr, addr, input, readOnly) @@ -1080,7 +1089,7 @@ func FheLibDiv(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != expected { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), expected) } @@ -1114,12 +1123,12 @@ func FheLibRem(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } input := toLibPrecompileInput(signature, scalar, lhsHash, rhsHash) out, err := FheLibRun(environment, addr, addr, input, readOnly) @@ -1131,7 +1140,7 @@ func FheLibRem(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != expected { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), expected) } @@ -1165,12 +1174,12 @@ func FheLibBitAnd(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } input := toLibPrecompileInput(signature, scalar, lhsHash, rhsHash) out, err := FheLibRun(environment, addr, addr, input, readOnly) @@ -1186,7 +1195,7 @@ func FheLibBitAnd(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != expected { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), expected) } @@ -1216,12 +1225,12 @@ func FheLibBitOr(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } input := toLibPrecompileInput(signature, scalar, lhsHash, rhsHash) out, err := FheLibRun(environment, addr, addr, input, readOnly) @@ -1237,7 +1246,7 @@ func FheLibBitOr(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != expected { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), expected) } @@ -1267,12 +1276,12 @@ func FheLibBitXor(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } input := toLibPrecompileInput(signature, scalar, lhsHash, rhsHash) out, err := FheLibRun(environment, addr, addr, input, readOnly) @@ -1288,7 +1297,7 @@ func FheLibBitXor(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != expected { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), expected) } @@ -1318,7 +1327,7 @@ func FheLibRand(t *testing.T, fheUintType FheUintType) { } hash := common.BytesToHash(out) - decrypted, err := environment.FhevmData().verifiedCiphertexts[hash].ciphertext.decrypt() + decrypted, err := environment.FhevmData().verifiedCiphertexts[hash].ciphertext.Decrypt() if err != nil { t.Fatalf(err.Error()) } @@ -1370,7 +1379,7 @@ func FheLibRandBounded(t *testing.T, fheUintType FheUintType, upperBound64 uint6 } hash := common.BytesToHash(out) - decrypted, err := environment.FhevmData().verifiedCiphertexts[hash].ciphertext.decrypt() + decrypted, err := environment.FhevmData().verifiedCiphertexts[hash].ciphertext.Decrypt() if err != nil { t.Fatalf(err.Error()) } @@ -1404,9 +1413,9 @@ func FheLibIfThenElse(t *testing.T, fheUintType FheUintType, condition uint64) { environment.depth = depth addr := common.Address{} readOnly := false - firstHash := verifyCiphertextInTestMemory(environment, condition, depth, FheUint8).getHash() - secondHash := verifyCiphertextInTestMemory(environment, second, depth, fheUintType).getHash() - thirdHash := verifyCiphertextInTestMemory(environment, third, depth, fheUintType).getHash() + firstHash := verifyCiphertextInTestMemory(environment, condition, depth, FheUint8).GetHash() + secondHash := verifyCiphertextInTestMemory(environment, second, depth, fheUintType).GetHash() + thirdHash := verifyCiphertextInTestMemory(environment, third, depth, fheUintType).GetHash() input := toLibPrecompileInputNoScalar(signature, firstHash, secondHash, thirdHash) out, err := FheLibRun(environment, addr, addr, input, readOnly) if err != nil { @@ -1417,7 +1426,7 @@ func FheLibIfThenElse(t *testing.T, fheUintType FheUintType, condition uint64) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || condition == 1 && decrypted.Uint64() != second || condition == 0 && decrypted.Uint64() != third { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), 1) } @@ -1452,11 +1461,11 @@ func LibTrivialEncrypt(t *testing.T, fheUintType FheUintType) { if err != nil { t.Fatalf(err.Error()) } - ct := new(tfheCiphertext).trivialEncrypt(value, fheUintType) - if common.BytesToHash(out) != ct.getHash() { + ct := new(TfheCiphertext).TrivialEncrypt(value, fheUintType) + if common.BytesToHash(out) != ct.GetHash() { t.Fatalf("output hash in verifyCipertext is incorrect") } - res := getVerifiedCiphertextFromEVM(environment, ct.getHash()) + res := getVerifiedCiphertextFromEVM(environment, ct.GetHash()) if res == nil { t.Fatalf("verifyCiphertext must have verified given ciphertext") } @@ -1483,7 +1492,7 @@ func LibDecrypt(t *testing.T, fheUintType FheUintType) { addr := common.Address{} readOnly := false input := make([]byte, 0) - hash := verifyCiphertextInTestMemory(environment, value, depth, fheUintType).getHash() + hash := verifyCiphertextInTestMemory(environment, value, depth, fheUintType).GetHash() input = append(input, signatureBytes...) input = append(input, hash.Bytes()...) out, err := FheLibRun(environment, addr, addr, input, readOnly) @@ -1559,7 +1568,7 @@ func TestLibCast(t *testing.T) { environment.ethCall = true toEncrypt := 7 fheUintType := FheUint8 - encCiphertext := verifyCiphertextInTestMemory(environment, uint64(toEncrypt), depth, fheUintType).getHash() + encCiphertext := verifyCiphertextInTestMemory(environment, uint64(toEncrypt), depth, fheUintType).GetHash() addr := common.Address{} readOnly := false input := make([]byte, 0) @@ -1594,12 +1603,12 @@ func FheAdd(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } input := toPrecompileInput(scalar, lhsHash, rhsHash) out, err := fheAddRun(environment, addr, addr, input, readOnly) @@ -1610,7 +1619,7 @@ func FheAdd(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != expected { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), expected) } @@ -1638,12 +1647,12 @@ func FheSub(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } input := toPrecompileInput(scalar, lhsHash, rhsHash) out, err := fheSubRun(environment, addr, addr, input, readOnly) @@ -1654,7 +1663,7 @@ func FheSub(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != expected { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), expected) } @@ -1682,12 +1691,12 @@ func FheMul(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } input := toPrecompileInput(scalar, lhsHash, rhsHash) out, err := fheMulRun(environment, addr, addr, input, readOnly) @@ -1698,7 +1707,7 @@ func FheMul(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != expected { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), expected) } @@ -1726,12 +1735,12 @@ func FheDiv(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } input := toPrecompileInput(scalar, lhsHash, rhsHash) out, err := fheDivRun(environment, addr, addr, input, readOnly) @@ -1743,7 +1752,7 @@ func FheDiv(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != expected { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), expected) } @@ -1776,12 +1785,12 @@ func FheRem(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } input := toPrecompileInput(scalar, lhsHash, rhsHash) out, err := fheRemRun(environment, addr, addr, input, readOnly) @@ -1793,7 +1802,7 @@ func FheRem(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != expected { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), expected) } @@ -1826,12 +1835,12 @@ func FheBitAnd(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } input := toPrecompileInput(scalar, lhsHash, rhsHash) out, err := fheBitAndRun(environment, addr, addr, input, readOnly) @@ -1847,7 +1856,7 @@ func FheBitAnd(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != expected { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), expected) } @@ -1876,12 +1885,12 @@ func FheBitOr(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } input := toPrecompileInput(scalar, lhsHash, rhsHash) out, err := fheBitOrRun(environment, addr, addr, input, readOnly) @@ -1897,7 +1906,7 @@ func FheBitOr(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != expected { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), expected) } @@ -1926,12 +1935,12 @@ func FheBitXor(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } input := toPrecompileInput(scalar, lhsHash, rhsHash) out, err := fheBitXorRun(environment, addr, addr, input, readOnly) @@ -1947,7 +1956,7 @@ func FheBitXor(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != expected { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), expected) } @@ -1976,12 +1985,12 @@ func FheShl(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } input := toPrecompileInput(scalar, lhsHash, rhsHash) out, err := fheShlRun(environment, addr, addr, input, readOnly) @@ -1992,7 +2001,7 @@ func FheShl(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != expected { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), expected) } @@ -2020,12 +2029,12 @@ func FheShr(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } input := toPrecompileInput(scalar, lhsHash, rhsHash) out, err := fheShrRun(environment, addr, addr, input, readOnly) @@ -2036,7 +2045,7 @@ func FheShr(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != expected { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), expected) } @@ -2063,12 +2072,12 @@ func FheEq(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } // lhs == rhs input1 := toPrecompileInput(scalar, lhsHash, rhsHash) @@ -2080,7 +2089,7 @@ func FheEq(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != 0 { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), 0) } @@ -2107,12 +2116,12 @@ func FheNe(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } // lhs == rhs input1 := toPrecompileInput(scalar, lhsHash, rhsHash) @@ -2124,7 +2133,7 @@ func FheNe(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != 1 { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), 1) } @@ -2151,12 +2160,12 @@ func FheGe(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } // lhs >= rhs input1 := toPrecompileInput(scalar, lhsHash, rhsHash) @@ -2168,7 +2177,7 @@ func FheGe(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != 1 { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), 1) } @@ -2185,7 +2194,7 @@ func FheGe(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err = res.ciphertext.decrypt() + decrypted, err = res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != 0 { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), 0) } @@ -2214,12 +2223,12 @@ func FheGt(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } // lhs > rhs input1 := toPrecompileInput(scalar, lhsHash, rhsHash) @@ -2231,7 +2240,7 @@ func FheGt(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != 1 { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), 1) } @@ -2249,7 +2258,7 @@ func FheGt(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err = res.ciphertext.decrypt() + decrypted, err = res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != 0 { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), 0) } @@ -2277,12 +2286,12 @@ func FheLe(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } // lhs <= rhs @@ -2295,7 +2304,7 @@ func FheLe(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != 0 { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), 0) } @@ -2313,7 +2322,7 @@ func FheLe(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err = res.ciphertext.decrypt() + decrypted, err = res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != 1 { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), 1) } @@ -2342,12 +2351,12 @@ func FheLt(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } // lhs < rhs @@ -2360,7 +2369,7 @@ func FheLt(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != 0 { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), 0) } @@ -2378,7 +2387,7 @@ func FheLt(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err = res.ciphertext.decrypt() + decrypted, err = res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != 1 { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), 1) } @@ -2407,12 +2416,12 @@ func FheMin(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } input := toPrecompileInput(scalar, lhsHash, rhsHash) @@ -2424,7 +2433,7 @@ func FheMin(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != rhs { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), rhs) } @@ -2441,7 +2450,7 @@ func FheMin(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err = res.ciphertext.decrypt() + decrypted, err = res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != rhs { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), rhs) } @@ -2470,12 +2479,12 @@ func FheMax(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() var rhsHash common.Hash if scalar { rhsHash = common.BytesToHash(big.NewInt(int64(rhs)).Bytes()) } else { - rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + rhsHash = verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() } input := toPrecompileInput(scalar, lhsHash, rhsHash) @@ -2487,7 +2496,7 @@ func FheMax(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != lhs { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), lhs) } @@ -2504,7 +2513,7 @@ func FheMax(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err = res.ciphertext.decrypt() + decrypted, err = res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != lhs { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), lhs) } @@ -2533,7 +2542,7 @@ func FheNeg(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - ptHash := verifyCiphertextInTestMemory(environment, pt, depth, fheUintType).getHash() + ptHash := verifyCiphertextInTestMemory(environment, pt, depth, fheUintType).GetHash() input := make([]byte, 0) input = append(input, ptHash.Bytes()...) @@ -2545,7 +2554,7 @@ func FheNeg(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != expected { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), expected) } @@ -2573,7 +2582,7 @@ func FheNot(t *testing.T, fheUintType FheUintType, scalar bool) { environment.depth = depth addr := common.Address{} readOnly := false - ptHash := verifyCiphertextInTestMemory(environment, pt, depth, fheUintType).getHash() + ptHash := verifyCiphertextInTestMemory(environment, pt, depth, fheUintType).GetHash() input := make([]byte, 0) input = append(input, ptHash.Bytes()...) @@ -2585,7 +2594,7 @@ func FheNot(t *testing.T, fheUintType FheUintType, scalar bool) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || decrypted.Uint64() != expected { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), expected) } @@ -2612,9 +2621,9 @@ func FheIfThenElse(t *testing.T, fheUintType FheUintType, condition uint64) { environment.depth = depth addr := common.Address{} readOnly := false - conditionHash := verifyCiphertextInTestMemory(environment, condition, depth, fheUintType).getHash() - lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).getHash() - rhsHash := verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).getHash() + conditionHash := verifyCiphertextInTestMemory(environment, condition, depth, fheUintType).GetHash() + lhsHash := verifyCiphertextInTestMemory(environment, lhs, depth, fheUintType).GetHash() + rhsHash := verifyCiphertextInTestMemory(environment, rhs, depth, fheUintType).GetHash() input1 := toPrecompileInputNoScalar(false, conditionHash, lhsHash, rhsHash) out, err := fheIfThenElseRun(environment, addr, addr, input1, readOnly) @@ -2625,7 +2634,7 @@ func FheIfThenElse(t *testing.T, fheUintType FheUintType, condition uint64) { if res == nil { t.Fatalf("output ciphertext is not found in verifiedCiphertexts") } - decrypted, err := res.ciphertext.decrypt() + decrypted, err := res.ciphertext.Decrypt() if err != nil || condition == 1 && decrypted.Uint64() != lhs || condition == 0 && decrypted.Uint64() != rhs { t.Fatalf("invalid decrypted result, decrypted %v != expected %v", decrypted.Uint64(), 0) } @@ -2648,7 +2657,7 @@ func Decrypt(t *testing.T, fheUintType FheUintType) { environment.depth = depth addr := common.Address{} readOnly := false - hash := verifyCiphertextInTestMemory(environment, value, depth, fheUintType).getHash() + hash := verifyCiphertextInTestMemory(environment, value, depth, fheUintType).GetHash() out, err := decryptRunWithoutKms(environment, addr, addr, hash.Bytes(), readOnly) if err != nil { t.Fatalf(err.Error()) @@ -2679,7 +2688,7 @@ func FheRand(t *testing.T, fheUintType FheUintType) { } hash := common.BytesToHash(out) - _, err = environment.FhevmData().verifiedCiphertexts[hash].ciphertext.decrypt() + _, err = environment.FhevmData().verifiedCiphertexts[hash].ciphertext.Decrypt() if err != nil { t.Fatalf(err.Error()) } @@ -2693,7 +2702,7 @@ func TestVerifyCiphertextInvalidType(t *testing.T) { readOnly := false invalidType := FheUintType(255) compact := encryptAndSerializeCompact(0, FheUint64) - input := append(compact, byte(invalidType)) + input := prepareInputForVerifyCiphertext(append(compact, byte(invalidType))) _, err := verifyCiphertextRun(environment, addr, addr, input, readOnly) if err == nil { t.Fatalf("verifyCiphertext must have failed on invalid ciphertext type") @@ -2725,7 +2734,7 @@ func TestCastInvalidType(t *testing.T) { addr := common.Address{} readOnly := false invalidType := FheUintType(255) - hash := verifyCiphertextInTestMemory(environment, 1, depth, FheUint8).getHash() + hash := verifyCiphertextInTestMemory(environment, 1, depth, FheUint8).GetHash() input := make([]byte, 0) input = append(input, hash.Bytes()...) input = append(input, byte(invalidType)) @@ -2743,7 +2752,7 @@ func TestVerifyCiphertextInvalidSize(t *testing.T) { readOnly := false ctType := FheUint32 compact := encryptAndSerializeCompact(0, ctType) - input := append(compact[:len(compact)-1], byte(ctType)) + input := prepareInputForVerifyCiphertext(append(compact[:len(compact)-1], byte(ctType))) _, err := verifyCiphertextRun(environment, addr, addr, input, readOnly) if err == nil { t.Fatalf("verifyCiphertext must have failed on invalid ciphertext size") @@ -2808,7 +2817,8 @@ func TestVerifyCiphertextBadCiphertext(t *testing.T) { environment.depth = depth addr := common.Address{} readOnly := false - _, err := verifyCiphertextRun(environment, addr, addr, make([]byte, 10), readOnly) + input := prepareInputForVerifyCiphertext(make([]byte, 10)) + _, err := verifyCiphertextRun(environment, addr, addr, input, readOnly) if err == nil { t.Fatalf("verifyCiphertext must fail on bad ciphertext input") } @@ -3622,7 +3632,7 @@ func TestUnknownCiphertextHandle(t *testing.T) { depth := 1 environment := newTestEVMEnvironment() environment.depth = depth - hash := verifyCiphertextInTestMemory(environment, 2, depth, FheUint8).getHash() + hash := verifyCiphertextInTestMemory(environment, 2, depth, FheUint8).GetHash() ct := getVerifiedCiphertext(environment, hash) if ct == nil { @@ -3641,7 +3651,7 @@ func TestCiphertextNotVerifiedWithoutReturn(t *testing.T) { environment := newTestEVMEnvironment() environment.depth = 1 verifiedDepth := 2 - hash := verifyCiphertextInTestMemory(environment, 1, verifiedDepth, FheUint8).getHash() + hash := verifyCiphertextInTestMemory(environment, 1, verifiedDepth, FheUint8).GetHash() ct := getVerifiedCiphertext(environment, hash) if ct != nil { @@ -3653,7 +3663,7 @@ func TestCiphertextNotAutomaticallyDelegated(t *testing.T) { environment := newTestEVMEnvironment() environment.depth = 3 verifiedDepth := 2 - hash := verifyCiphertextInTestMemory(environment, 1, verifiedDepth, FheUint8).getHash() + hash := verifyCiphertextInTestMemory(environment, 1, verifiedDepth, FheUint8).GetHash() ct := getVerifiedCiphertext(environment, hash) if ct != nil { @@ -3664,7 +3674,7 @@ func TestCiphertextNotAutomaticallyDelegated(t *testing.T) { func TestCiphertextVerificationConditions(t *testing.T) { environment := newTestEVMEnvironment() verifiedDepth := 2 - hash := verifyCiphertextInTestMemory(environment, 1, verifiedDepth, FheUint8).getHash() + hash := verifyCiphertextInTestMemory(environment, 1, verifiedDepth, FheUint8).GetHash() environment.depth = verifiedDepth ctPtr := getVerifiedCiphertext(environment, hash) @@ -3885,7 +3895,7 @@ func TestLibOneTrueOptimisticRequire(t *testing.T) { addr := common.Address{} readOnly := false input := make([]byte, 0) - hash := verifyCiphertextInTestMemory(environment, value, depth, FheUint8).getHash() + hash := verifyCiphertextInTestMemory(environment, value, depth, FheUint8).GetHash() input = append(input, signatureBytes...) input = append(input, hash.Bytes()...) out, err := FheLibRun(environment, addr, addr, input, readOnly) @@ -3912,7 +3922,7 @@ func TestOneFalseOptimisticRequire(t *testing.T) { environment.depth = depth addr := common.Address{} readOnly := false - hash := verifyCiphertextInTestMemory(environment, value, depth, FheUint8).getHash() + hash := verifyCiphertextInTestMemory(environment, value, depth, FheUint8).GetHash() out, err := optimisticRequireRun(environment, addr, addr, hash.Bytes(), readOnly) if err != nil { t.Fatalf(err.Error()) @@ -3936,14 +3946,14 @@ func TestTwoTrueOptimisticRequires(t *testing.T) { environment.depth = depth addr := common.Address{} readOnly := false - hash := verifyCiphertextInTestMemory(environment, value, depth, FheUint8).getHash() + hash := verifyCiphertextInTestMemory(environment, value, depth, FheUint8).GetHash() out, err := optimisticRequireRun(environment, addr, addr, hash.Bytes(), readOnly) if err != nil { t.Fatalf(err.Error()) } else if len(out) != 0 { t.Fatalf("require expected output len of 0, got %v", len(out)) } - hash = verifyCiphertextInTestMemory(environment, value, depth, FheUint8).getHash() + hash = verifyCiphertextInTestMemory(environment, value, depth, FheUint8).GetHash() out, err = optimisticRequireRun(environment, addr, addr, hash.Bytes(), readOnly) if err != nil { t.Fatalf(err.Error()) @@ -3968,7 +3978,7 @@ func TestOptimisticRequireTwiceOnSameCiphertext(t *testing.T) { addr := common.Address{} readOnly := false ct := verifyCiphertextInTestMemory(environment, value, depth, FheUint8) - hash := ct.getHash() + hash := ct.GetHash() out, err := optimisticRequireRun(environment, addr, addr, hash.Bytes(), readOnly) if err != nil { t.Fatalf(err.Error()) @@ -3997,14 +4007,14 @@ func TestOneFalseAndOneTrueOptimisticRequire(t *testing.T) { environment.depth = depth addr := common.Address{} readOnly := false - hash := verifyCiphertextInTestMemory(environment, 0, depth, FheUint8).getHash() + hash := verifyCiphertextInTestMemory(environment, 0, depth, FheUint8).GetHash() out, err := optimisticRequireRun(environment, addr, addr, hash.Bytes(), readOnly) if err != nil { t.Fatalf(err.Error()) } else if len(out) != 0 { t.Fatalf("require expected output len of 0, got %v", len(out)) } - hash = verifyCiphertextInTestMemory(environment, 1, depth, FheUint8).getHash() + hash = verifyCiphertextInTestMemory(environment, 1, depth, FheUint8).GetHash() out, err = optimisticRequireRun(environment, addr, addr, hash.Bytes(), readOnly) if err != nil { t.Fatalf(err.Error()) @@ -4028,7 +4038,7 @@ func TestDecryptWithFalseOptimisticRequire(t *testing.T) { addr := common.Address{} readOnly := false // Call optimistic require with a false value and expect it succeeds. - hash := verifyCiphertextInTestMemory(environment, 0, depth, FheUint8).getHash() + hash := verifyCiphertextInTestMemory(environment, 0, depth, FheUint8).GetHash() out, err := optimisticRequireRun(environment, addr, addr, hash.Bytes(), readOnly) if err != nil { t.Fatalf(err.Error()) @@ -4053,7 +4063,7 @@ func TestDecryptWithTrueOptimisticRequire(t *testing.T) { addr := common.Address{} readOnly := false // Call optimistic require with a false value and expect it succeeds. - hash := verifyCiphertextInTestMemory(environment, 1, depth, FheUint8).getHash() + hash := verifyCiphertextInTestMemory(environment, 1, depth, FheUint8).GetHash() out, err := optimisticRequireRun(environment, addr, addr, hash.Bytes(), readOnly) if err != nil { t.Fatalf(err.Error()) @@ -4082,7 +4092,7 @@ func TestDecryptInTransactionDisabled(t *testing.T) { environment.fhevmParams.DisableDecryptionsInTransaction = true addr := common.Address{} readOnly := false - hash := verifyCiphertextInTestMemory(environment, 1, depth, FheUint8).getHash() + hash := verifyCiphertextInTestMemory(environment, 1, depth, FheUint8).GetHash() // Call decrypt and expect it to fail due to disabling of decryptions during commit _, err := decryptRunWithoutKms(environment, addr, addr, hash.Bytes(), readOnly) if err == nil { diff --git a/fhevm/evm.go b/fhevm/evm.go index eed24b2..660b287 100644 --- a/fhevm/evm.go +++ b/fhevm/evm.go @@ -1,8 +1,6 @@ package fhevm import ( - "encoding/binary" - "errors" "fmt" "math/big" @@ -53,73 +51,12 @@ func (*DefaultLogger) Error(msg string, keyvals ...interface{}) { fmt.Println("Error: "+msg, toString(keyvals...)) } -func makeKeccakSignature(input string) uint32 { - return binary.BigEndian.Uint32(crypto.Keccak256([]byte(input))[0:4]) -} - -func isScalarOp(input []byte) (bool, error) { - if len(input) != 65 { - return false, errors.New("input needs to contain two 256-bit sized values and 1 8-bit value") - } - isScalar := (input[64] == 1) - return isScalar, nil -} - func getVerifiedCiphertext(environment EVMEnvironment, ciphertextHash common.Hash) *verifiedCiphertext { return getVerifiedCiphertextFromEVM(environment, ciphertextHash) } -func get2VerifiedOperands(environment EVMEnvironment, input []byte) (lhs *verifiedCiphertext, rhs *verifiedCiphertext, err error) { - if len(input) != 65 { - return nil, nil, errors.New("input needs to contain two 256-bit sized values and 1 8-bit value") - } - lhs = getVerifiedCiphertext(environment, common.BytesToHash(input[0:32])) - if lhs == nil { - return nil, nil, errors.New("unverified ciphertext handle") - } - rhs = getVerifiedCiphertext(environment, common.BytesToHash(input[32:64])) - if rhs == nil { - return nil, nil, errors.New("unverified ciphertext handle") - } - err = nil - return -} - -func get3VerifiedOperands(environment EVMEnvironment, input []byte) (first *verifiedCiphertext, second *verifiedCiphertext, third *verifiedCiphertext, err error) { - if len(input) != 96 { - return nil, nil, nil, errors.New("input needs to contain three 256-bit sized values") - } - first = getVerifiedCiphertext(environment, common.BytesToHash(input[0:32])) - if first == nil { - return nil, nil, nil, errors.New("unverified ciphertext handle") - } - second = getVerifiedCiphertext(environment, common.BytesToHash(input[32:64])) - if second == nil { - return nil, nil, nil, errors.New("unverified ciphertext handle") - } - third = getVerifiedCiphertext(environment, common.BytesToHash(input[64:96])) - if third == nil { - return nil, nil, nil, errors.New("unverified ciphertext handle") - } - err = nil - return -} - -func getScalarOperands(environment EVMEnvironment, input []byte) (lhs *verifiedCiphertext, rhs *big.Int, err error) { - if len(input) != 65 { - return nil, nil, errors.New("input needs to contain two 256-bit sized values and 1 8-bit value") - } - lhs = getVerifiedCiphertext(environment, common.BytesToHash(input[0:32])) - if lhs == nil { - return nil, nil, errors.New("unverified ciphertext handle") - } - rhs = &big.Int{} - rhs.SetBytes(input[32:64]) - return -} - -func importCiphertextToEVMAtDepth(environment EVMEnvironment, ct *tfheCiphertext, depth int) *verifiedCiphertext { - existing, ok := environment.FhevmData().verifiedCiphertexts[ct.getHash()] +func importCiphertextToEVMAtDepth(environment EVMEnvironment, ct *TfheCiphertext, depth int) *verifiedCiphertext { + existing, ok := environment.FhevmData().verifiedCiphertexts[ct.GetHash()] if ok { existing.verifiedDepths.add(depth) return existing @@ -130,16 +67,16 @@ func importCiphertextToEVMAtDepth(environment EVMEnvironment, ct *tfheCiphertext verifiedDepths, ct, } - environment.FhevmData().verifiedCiphertexts[ct.getHash()] = new + environment.FhevmData().verifiedCiphertexts[ct.GetHash()] = new return new } } -func importCiphertextToEVM(environment EVMEnvironment, ct *tfheCiphertext) *verifiedCiphertext { +func importCiphertextToEVM(environment EVMEnvironment, ct *TfheCiphertext) *verifiedCiphertext { return importCiphertextToEVMAtDepth(environment, ct, environment.GetDepth()) } -func importCiphertext(environment EVMEnvironment, ct *tfheCiphertext) *verifiedCiphertext { +func importCiphertext(environment EVMEnvironment, ct *TfheCiphertext) *verifiedCiphertext { return importCiphertextToEVM(environment, ct) } @@ -147,33 +84,13 @@ func importRandomCiphertext(environment EVMEnvironment, t FheUintType) []byte { nextCtHash := &environment.FhevmData().nextCiphertextHashOnGasEst ctHashBytes := crypto.Keccak256(nextCtHash.Bytes()) handle := common.BytesToHash(ctHashBytes) - ct := new(tfheCiphertext) + ct := new(TfheCiphertext) ct.fheUintType = t ct.hash = &handle importCiphertext(environment, ct) temp := nextCtHash.Clone() nextCtHash.Add(temp, uint256.NewInt(1)) - return ct.getHash().Bytes() -} - -func minInt(a int, b int) int { - if a < b { - return a - } - return b -} - -// Return a memory with a layout that matches the `bytes` EVM type, namely: -// - 32 byte integer in big-endian order as length -// - the actual bytes in the `bytes` value -// - add zero byte padding until nearest multiple of 32 -func toEVMBytes(input []byte) []byte { - arrLen := uint64(len(input)) - lenBytes32 := uint256.NewInt(arrLen).Bytes32() - ret := make([]byte, 0, arrLen+32) - ret = append(ret, lenBytes32[:]...) - ret = append(ret, input...) - return ret + return ct.GetHash().Bytes() } func InitFhevm(accessibleState EVMEnvironment) { @@ -187,19 +104,6 @@ func persistFhePubKeyHash(accessibleState EVMEnvironment) { } } -// apply padding to slice to the multiple of 32 -func padArrayTo32Multiple(input []byte) []byte { - modRes := len(input) % 32 - if modRes > 0 { - padding := 32 - modRes - for padding > 0 { - padding-- - input = append(input, 0x0) - } - } - return input -} - 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) diff --git a/fhevm/fhelib.go b/fhevm/fhelib.go new file mode 100644 index 0000000..77ebb48 --- /dev/null +++ b/fhevm/fhelib.go @@ -0,0 +1,318 @@ +package fhevm + +import ( + "encoding/binary" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/holiman/uint256" +) + +func makeKeccakSignature(input string) uint32 { + return binary.BigEndian.Uint32(crypto.Keccak256([]byte(input))[0:4]) +} + +// These are the signatures of the different functions available in the fheLib. +// Calls to the fheLib should specify the signature of the function to call + +var signatureFheAdd = makeKeccakSignature("fheAdd(uint256,uint256,bytes1)") +var signatureFheSub = makeKeccakSignature("fheSub(uint256,uint256,bytes1)") +var signatureFheMul = makeKeccakSignature("fheMul(uint256,uint256,bytes1)") +var signatureFheDiv = makeKeccakSignature("fheDiv(uint256,uint256,bytes1)") +var signatureFheRem = makeKeccakSignature("fheRem(uint256,uint256,bytes1)") +var signatureFheMin = makeKeccakSignature("fheMin(uint256,uint256,bytes1)") +var signatureFheMax = makeKeccakSignature("fheMax(uint256,uint256,bytes1)") +var signatureFheRand = makeKeccakSignature("fheRand(bytes1)") +var signatureFheRandBounded = makeKeccakSignature("fheRandBounded(uint256,bytes1)") +var signatureCast = makeKeccakSignature("cast(uint256,bytes1)") +var signatureFheLe = makeKeccakSignature("fheLe(uint256,uint256,bytes1)") +var signatureFheLt = makeKeccakSignature("fheLt(uint256,uint256,bytes1)") +var signatureFheEq = makeKeccakSignature("fheEq(uint256,uint256,bytes1)") +var signatureFheGe = makeKeccakSignature("fheGe(uint256,uint256,bytes1)") +var signatureFheGt = makeKeccakSignature("fheGt(uint256,uint256,bytes1)") +var signatureFheShl = makeKeccakSignature("fheShl(uint256,uint256,bytes1)") +var signatureFheShr = makeKeccakSignature("fheShr(uint256,uint256,bytes1)") +var signatureFheNe = makeKeccakSignature("fheNe(uint256,uint256,bytes1)") +var signatureFheNeg = makeKeccakSignature("fheNeg(uint256)") +var signatureFheNot = makeKeccakSignature("fheNot(uint256)") +var signatureFheBitAnd = makeKeccakSignature("fheBitAnd(uint256,uint256,bytes1)") +var signatureFheBitOr = makeKeccakSignature("fheBitOr(uint256,uint256,bytes1)") +var signatureFheBitXor = makeKeccakSignature("fheBitXor(uint256,uint256,bytes1)") +var signatureFheIfThenElse = makeKeccakSignature("fheIfThenElse(uint256,uint256,uint256)") +var signatureFhePubKey = makeKeccakSignature("fhePubKey(bytes1)") +var signatureTrivialEncrypt = makeKeccakSignature("trivialEncrypt(uint256,bytes1)") +var signatureDecrypt = makeKeccakSignature("decrypt(uint256)") +var signatureReencrypt = makeKeccakSignature("reencrypt(uint256,uint256)") +var signatureVerifyCiphertext = makeKeccakSignature("verifyCiphertext(bytes)") +var signatureOptimisticRequire = makeKeccakSignature("optimisticRequire(uint256)") + +type fheLibPrecompileMethod struct { + name string + requiredGasFunction func(environment EVMEnvironment, input []byte) uint64 + runFunction func(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) +} + +func (fheLibMethod *fheLibPrecompileMethod) Name() string { + return fheLibMethod.name +} + +func (fheLibMethod *fheLibPrecompileMethod) RequiredGas(environment EVMEnvironment, input []byte) uint64 { + return fheLibMethod.requiredGasFunction(environment, input) +} + +func (fheLibMethod *fheLibPrecompileMethod) Run(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + return fheLibMethod.runFunction(environment, caller, addr, input, readOnly) +} + +// Mapping between function signatures and the functions to call +var signatureToFheLibMethod = map[uint32]*fheLibPrecompileMethod{} + +func GetFheLibMethod(signature uint32) (fheLibMethod *fheLibPrecompileMethod, found bool) { + fheLibMethod, found = signatureToFheLibMethod[signature] + return +} + +func init() { + signatureToFheLibMethod[signatureFheAdd] = &fheLibPrecompileMethod{ + name: "fheAdd", + requiredGasFunction: fheAddSubRequiredGas, + runFunction: fheAddRun, + } + signatureToFheLibMethod[signatureFheSub] = &fheLibPrecompileMethod{ + name: "fheSub", + requiredGasFunction: fheAddSubRequiredGas, + runFunction: fheSubRun, + } + signatureToFheLibMethod[signatureFheMul] = &fheLibPrecompileMethod{ + name: "fheMul", + requiredGasFunction: fheMulRequiredGas, + runFunction: fheMulRun, + } + signatureToFheLibMethod[signatureFheDiv] = &fheLibPrecompileMethod{ + name: "fheDiv", + requiredGasFunction: fheDivRequiredGas, + runFunction: fheDivRun, + } + signatureToFheLibMethod[signatureFheRem] = &fheLibPrecompileMethod{ + name: "fheRem", + requiredGasFunction: fheRemRequiredGas, + runFunction: fheRemRun, + } + signatureToFheLibMethod[signatureFheMin] = &fheLibPrecompileMethod{ + name: "fheMin", + requiredGasFunction: fheMinRequiredGas, + runFunction: fheMinRun, + } + signatureToFheLibMethod[signatureFheMax] = &fheLibPrecompileMethod{ + name: "fheMax", + requiredGasFunction: fheMaxRequiredGas, + runFunction: fheMaxRun, + } + signatureToFheLibMethod[signatureFheRand] = &fheLibPrecompileMethod{ + name: "fheRand", + requiredGasFunction: fheRandRequiredGas, + runFunction: fheRandRun, + } + signatureToFheLibMethod[signatureFheRandBounded] = &fheLibPrecompileMethod{ + name: "fheRandBounded", + requiredGasFunction: fheRandBoundedRequiredGas, + runFunction: fheRandBoundedRun, + } + signatureToFheLibMethod[signatureCast] = &fheLibPrecompileMethod{ + name: "fheCast", + requiredGasFunction: castRequiredGas, + runFunction: castRun, + } + signatureToFheLibMethod[signatureFheLe] = &fheLibPrecompileMethod{ + name: "fheLe", + requiredGasFunction: fheLeRequiredGas, + runFunction: fheLeRun, + } + signatureToFheLibMethod[signatureFheLt] = &fheLibPrecompileMethod{ + name: "fheLt", + requiredGasFunction: fheLtRequiredGas, + runFunction: fheLtRun, + } + signatureToFheLibMethod[signatureFheEq] = &fheLibPrecompileMethod{ + name: "fheEq", + requiredGasFunction: fheEqRequiredGas, + runFunction: fheEqRun, + } + signatureToFheLibMethod[signatureFheGe] = &fheLibPrecompileMethod{ + name: "fheGe", + requiredGasFunction: fheGeRequiredGas, + runFunction: fheGeRun, + } + signatureToFheLibMethod[signatureFheGt] = &fheLibPrecompileMethod{ + name: "fheGt", + requiredGasFunction: fheGtRequiredGas, + runFunction: fheGtRun, + } + signatureToFheLibMethod[signatureFheShl] = &fheLibPrecompileMethod{ + name: "fheShl", + requiredGasFunction: fheShlRequiredGas, + runFunction: fheShlRun, + } + signatureToFheLibMethod[signatureFheShr] = &fheLibPrecompileMethod{ + name: "fheShr", + requiredGasFunction: fheShrRequiredGas, + runFunction: fheShrRun, + } + signatureToFheLibMethod[signatureFheNe] = &fheLibPrecompileMethod{ + name: "fheNe", + requiredGasFunction: fheNeRequiredGas, + runFunction: fheNeRun, + } + signatureToFheLibMethod[signatureFheNeg] = &fheLibPrecompileMethod{ + name: "fheNeg", + requiredGasFunction: fheNegRequiredGas, + runFunction: fheNegRun, + } + signatureToFheLibMethod[signatureFheNot] = &fheLibPrecompileMethod{ + name: "fheNot", + requiredGasFunction: fheNotRequiredGas, + runFunction: fheNotRun, + } + signatureToFheLibMethod[signatureFheBitAnd] = &fheLibPrecompileMethod{ + name: "fheBitAnd", + requiredGasFunction: fheBitAndRequiredGas, + runFunction: fheBitAndRun, + } + signatureToFheLibMethod[signatureFheBitOr] = &fheLibPrecompileMethod{ + name: "fheBitOr", + requiredGasFunction: fheBitOrRequiredGas, + runFunction: fheBitOrRun, + } + signatureToFheLibMethod[signatureFheBitXor] = &fheLibPrecompileMethod{ + name: "fheBitXor", + requiredGasFunction: fheBitXorRequiredGas, + runFunction: fheBitXorRun, + } + signatureToFheLibMethod[signatureFheIfThenElse] = &fheLibPrecompileMethod{ + name: "fheIfThenElse", + requiredGasFunction: fheIfThenElseRequiredGas, + runFunction: fheIfThenElseRun, + } + signatureToFheLibMethod[signatureFhePubKey] = &fheLibPrecompileMethod{ + name: "fhePubKey", + requiredGasFunction: fhePubKeyRequiredGas, + runFunction: fhePubKeyRun, + } + signatureToFheLibMethod[signatureTrivialEncrypt] = &fheLibPrecompileMethod{ + name: "trivialEncrypt", + requiredGasFunction: trivialEncryptRequiredGas, + runFunction: trivialEncryptRun, + } + signatureToFheLibMethod[signatureDecrypt] = &fheLibPrecompileMethod{ + name: "decrypt", + requiredGasFunction: decryptRequiredGas, + runFunction: decryptRun, + } + signatureToFheLibMethod[signatureReencrypt] = &fheLibPrecompileMethod{ + name: "reencrypt", + requiredGasFunction: reencryptRequiredGas, + runFunction: reencryptRun, + } + signatureToFheLibMethod[signatureVerifyCiphertext] = &fheLibPrecompileMethod{ + name: "verifyCiphertext", + requiredGasFunction: verifyCiphertextRequiredGas, + runFunction: verifyCiphertextRun, + } + signatureToFheLibMethod[signatureOptimisticRequire] = &fheLibPrecompileMethod{ + name: "optimisticRequire", + requiredGasFunction: optimisticRequireRequiredGas, + runFunction: optimisticRequireRun, + } +} + +func minInt(a int, b int) int { + if a < b { + return a + } + return b +} + +// apply padding to slice to the multiple of 32 +func padArrayTo32Multiple(input []byte) []byte { + modRes := len(input) % 32 + if modRes > 0 { + padding := 32 - modRes + for padding > 0 { + padding-- + input = append(input, 0x0) + } + } + return input +} + +// Return a memory with a layout that matches the `bytes` EVM type, namely: +// - 32 byte integer in big-endian order as length +// - the actual bytes in the `bytes` value +// - add zero byte padding until nearest multiple of 32 +func toEVMBytes(input []byte) []byte { + arrLen := uint64(len(input)) + lenBytes32 := uint256.NewInt(arrLen).Bytes32() + ret := make([]byte, 0, arrLen+32) + ret = append(ret, lenBytes32[:]...) + ret = append(ret, input...) + return ret +} + +func get2VerifiedOperands(environment EVMEnvironment, input []byte) (lhs *verifiedCiphertext, rhs *verifiedCiphertext, err error) { + if len(input) != 65 { + return nil, nil, errors.New("input needs to contain two 256-bit sized values and 1 8-bit value") + } + lhs = getVerifiedCiphertext(environment, common.BytesToHash(input[0:32])) + if lhs == nil { + return nil, nil, errors.New("unverified ciphertext handle") + } + rhs = getVerifiedCiphertext(environment, common.BytesToHash(input[32:64])) + if rhs == nil { + return nil, nil, errors.New("unverified ciphertext handle") + } + err = nil + return +} + +func isScalarOp(input []byte) (bool, error) { + if len(input) != 65 { + return false, errors.New("input needs to contain two 256-bit sized values and 1 8-bit value") + } + isScalar := (input[64] == 1) + return isScalar, nil +} + +func get3VerifiedOperands(environment EVMEnvironment, input []byte) (first *verifiedCiphertext, second *verifiedCiphertext, third *verifiedCiphertext, err error) { + if len(input) != 96 { + return nil, nil, nil, errors.New("input needs to contain three 256-bit sized values") + } + first = getVerifiedCiphertext(environment, common.BytesToHash(input[0:32])) + if first == nil { + return nil, nil, nil, errors.New("unverified ciphertext handle") + } + second = getVerifiedCiphertext(environment, common.BytesToHash(input[32:64])) + if second == nil { + return nil, nil, nil, errors.New("unverified ciphertext handle") + } + third = getVerifiedCiphertext(environment, common.BytesToHash(input[64:96])) + if third == nil { + return nil, nil, nil, errors.New("unverified ciphertext handle") + } + err = nil + return +} + +func getScalarOperands(environment EVMEnvironment, input []byte) (lhs *verifiedCiphertext, rhs *big.Int, err error) { + if len(input) != 65 { + return nil, nil, errors.New("input needs to contain two 256-bit sized values and 1 8-bit value") + } + lhs = getVerifiedCiphertext(environment, common.BytesToHash(input[0:32])) + if lhs == nil { + return nil, nil, errors.New("unverified ciphertext handle") + } + rhs = &big.Int{} + rhs.SetBytes(input[32:64]) + return +} diff --git a/fhevm/fhelib_required_gas.go b/fhevm/fhelib_required_gas.go new file mode 100644 index 0000000..85af89d --- /dev/null +++ b/fhevm/fhelib_required_gas.go @@ -0,0 +1,476 @@ +package fhevm + +import ( + "encoding/hex" + "fmt" + "math/bits" + + "github.com/ethereum/go-ethereum/common" + "github.com/holiman/uint256" +) + +func fheAddSubRequiredGas(environment EVMEnvironment, input []byte) uint64 { + input = input[:minInt(65, len(input))] + + logger := environment.GetLogger() + isScalar, err := isScalarOp(input) + if err != nil { + logger.Error("fheAdd/Sub RequiredGas() can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) + return 0 + } + var lhs, rhs *verifiedCiphertext + if !isScalar { + lhs, rhs, err = get2VerifiedOperands(environment, input) + if err != nil { + logger.Error("fheAdd/Sub RequiredGas() ciphertext inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return 0 + } + if lhs.fheUintType() != rhs.fheUintType() { + logger.Error("fheAdd/Sub RequiredGas() operand type mismatch", "lhs", lhs.fheUintType(), "rhs", rhs.fheUintType()) + return 0 + } + } else { + lhs, _, err = getScalarOperands(environment, input) + if err != nil { + logger.Error("fheAdd/Sub RequiredGas() scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return 0 + } + } + + return environment.FhevmParams().GasCosts.FheAddSub[lhs.fheUintType()] +} + +func fheMulRequiredGas(environment EVMEnvironment, input []byte) uint64 { + input = input[:minInt(65, len(input))] + + logger := environment.GetLogger() + isScalar, err := isScalarOp(input) + if err != nil { + logger.Error("fheMul RequiredGas() can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) + return 0 + } + var lhs, rhs *verifiedCiphertext + if !isScalar { + lhs, rhs, err = get2VerifiedOperands(environment, input) + if err != nil { + logger.Error("fheMul RequiredGas() ciphertext inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return 0 + } + if lhs.fheUintType() != rhs.fheUintType() { + logger.Error("fheMul RequiredGas() operand type mismatch", "lhs", lhs.fheUintType(), "rhs", rhs.fheUintType()) + return 0 + } + return environment.FhevmParams().GasCosts.FheMul[lhs.fheUintType()] + } else { + lhs, _, err = getScalarOperands(environment, input) + if err != nil { + logger.Error("fheMul RequiredGas() scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return 0 + } + return environment.FhevmParams().GasCosts.FheScalarMul[lhs.fheUintType()] + } +} + +func fheLeRequiredGas(environment EVMEnvironment, input []byte) uint64 { + input = input[:minInt(65, len(input))] + + logger := environment.GetLogger() + isScalar, err := isScalarOp(input) + if err != nil { + logger.Error("comparison RequiredGas() can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) + return 0 + } + var lhs, rhs *verifiedCiphertext + if !isScalar { + lhs, rhs, err = get2VerifiedOperands(environment, input) + if err != nil { + logger.Error("comparison RequiredGas() ciphertext inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return 0 + } + if lhs.fheUintType() != rhs.fheUintType() { + logger.Error("comparison RequiredGas() operand type mismatch", "lhs", lhs.fheUintType(), "rhs", rhs.fheUintType()) + return 0 + } + } else { + lhs, _, err = getScalarOperands(environment, input) + if err != nil { + logger.Error("comparison RequiredGas() scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return 0 + } + } + return environment.FhevmParams().GasCosts.FheLe[lhs.fheUintType()] +} + +func fheLtRequiredGas(environment EVMEnvironment, input []byte) uint64 { + // Implement in terms of le, because le and lt costs are currently the same. + return fheLeRequiredGas(environment, input) +} + +func fheEqRequiredGas(environment EVMEnvironment, input []byte) uint64 { + // Implement in terms of le, because comparison costs are currently the same. + return fheLeRequiredGas(environment, input) +} + +func fheGeRequiredGas(environment EVMEnvironment, input []byte) uint64 { + // Implement in terms of le, because comparison costs are currently the same. + return fheLeRequiredGas(environment, input) +} + +func fheGtRequiredGas(environment EVMEnvironment, input []byte) uint64 { + // Implement in terms of le, because comparison costs are currently the same. + return fheLeRequiredGas(environment, input) +} + +func fheNeRequiredGas(environment EVMEnvironment, input []byte) uint64 { + // Implement in terms of le, because comparison costs are currently the same. + return fheLeRequiredGas(environment, input) +} + +func fheShlRequiredGas(environment EVMEnvironment, input []byte) uint64 { + input = input[:minInt(65, len(input))] + + logger := environment.GetLogger() + isScalar, err := isScalarOp(input) + if err != nil { + 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 *verifiedCiphertext + if !isScalar { + lhs, rhs, err = get2VerifiedOperands(environment, input) + if err != nil { + logger.Error("fheShift RequiredGas() ciphertext inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return 0 + } + if lhs.fheUintType() != rhs.fheUintType() { + logger.Error("fheShift RequiredGas() operand type mismatch", "lhs", lhs.fheUintType(), "rhs", rhs.fheUintType()) + return 0 + } + return environment.FhevmParams().GasCosts.FheShift[lhs.fheUintType()] + } else { + lhs, _, err = getScalarOperands(environment, input) + if err != nil { + logger.Error("fheShift RequiredGas() scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return 0 + } + return environment.FhevmParams().GasCosts.FheScalarShift[lhs.fheUintType()] + } +} + +func fheShrRequiredGas(environment EVMEnvironment, input []byte) uint64 { + // Implement in terms of shl, because comparison costs are currently the same. + return fheShlRequiredGas(environment, input) +} + +func fheMinRequiredGas(environment EVMEnvironment, input []byte) uint64 { + input = input[:minInt(65, len(input))] + + logger := environment.GetLogger() + isScalar, err := isScalarOp(input) + if err != nil { + 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 *verifiedCiphertext + if !isScalar { + lhs, rhs, err = get2VerifiedOperands(environment, input) + if err != nil { + logger.Error("fheMin/Max RequiredGas() ciphertext inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return 0 + } + if lhs.fheUintType() != rhs.fheUintType() { + logger.Error("fheMin/Max RequiredGas() operand type mismatch", "lhs", lhs.fheUintType(), "rhs", rhs.fheUintType()) + return 0 + } + return environment.FhevmParams().GasCosts.FheMinMax[lhs.fheUintType()] + } else { + lhs, _, err = getScalarOperands(environment, input) + if err != nil { + logger.Error("fheMin/Max RequiredGas() scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return 0 + } + return environment.FhevmParams().GasCosts.FheScalarMinMax[lhs.fheUintType()] + } +} + +func fheMaxRequiredGas(environment EVMEnvironment, input []byte) uint64 { + // Implement in terms of min, because costs are currently the same. + return fheMinRequiredGas(environment, input) +} + +func fheNegRequiredGas(environment EVMEnvironment, input []byte) uint64 { + input = input[:minInt(32, len(input))] + + logger := environment.GetLogger() + if len(input) != 32 { + logger.Error("fheNeg input needs to contain one 256-bit sized value", "input", hex.EncodeToString(input)) + return 0 + } + ct := getVerifiedCiphertext(environment, common.BytesToHash(input[0:32])) + if ct == nil { + logger.Error("fheNeg input not verified", "input", hex.EncodeToString(input)) + return 0 + } + return environment.FhevmParams().GasCosts.FheNeg[ct.fheUintType()] +} + +func fheNotRequiredGas(environment EVMEnvironment, input []byte) uint64 { + input = input[:minInt(32, len(input))] + + logger := environment.GetLogger() + if len(input) != 32 { + logger.Error("fheNot input needs to contain one 256-bit sized value", "input", hex.EncodeToString(input)) + return 0 + } + ct := getVerifiedCiphertext(environment, common.BytesToHash(input[0:32])) + if ct == nil { + logger.Error("fheNot input not verified", "input", hex.EncodeToString(input)) + return 0 + } + return environment.FhevmParams().GasCosts.FheNot[ct.fheUintType()] +} + +func fheDivRequiredGas(environment EVMEnvironment, input []byte) uint64 { + input = input[:minInt(65, len(input))] + + logger := environment.GetLogger() + isScalar, err := isScalarOp(input) + if err != nil { + logger.Error("fheDiv RequiredGas() cannot detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) + return 0 + } + var lhs *verifiedCiphertext + if !isScalar { + logger.Error("fheDiv RequiredGas() only scalar in division is supported, two ciphertexts received", "input", hex.EncodeToString(input)) + return 0 + } else { + lhs, _, err = getScalarOperands(environment, input) + if err != nil { + logger.Error("fheDiv RequiredGas() scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return 0 + } + return environment.FhevmParams().GasCosts.FheScalarDiv[lhs.fheUintType()] + } +} + +func fheRemRequiredGas(environment EVMEnvironment, input []byte) uint64 { + input = input[:minInt(65, len(input))] + + logger := environment.GetLogger() + isScalar, err := isScalarOp(input) + if err != nil { + logger.Error("fheRem RequiredGas() cannot detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) + return 0 + } + var lhs *verifiedCiphertext + if !isScalar { + logger.Error("fheRem RequiredGas() only scalar in division is supported, two ciphertexts received", "input", hex.EncodeToString(input)) + return 0 + } else { + lhs, _, err = getScalarOperands(environment, input) + if err != nil { + logger.Error("fheRem RequiredGas() scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return 0 + } + return environment.FhevmParams().GasCosts.FheScalarRem[lhs.fheUintType()] + } +} + +func fheBitAndRequiredGas(environment EVMEnvironment, input []byte) uint64 { + input = input[:minInt(65, len(input))] + + logger := environment.GetLogger() + + isScalar, err := isScalarOp(input) + if err != nil { + logger.Error("Bitwise op RequiredGas() can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) + return 0 + } + + if isScalar { + msg := "Bitwise op RequiredGas() scalar op not supported" + logger.Error(msg) + return 0 + } + + lhs, rhs, err := get2VerifiedOperands(environment, input) + if err != nil { + logger.Error("Bitwise op RequiredGas() inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return 0 + } + if lhs.fheUintType() != rhs.fheUintType() { + logger.Error("Bitwise op RequiredGas() operand type mismatch", "lhs", lhs.fheUintType(), "rhs", rhs.fheUintType()) + return 0 + } + return environment.FhevmParams().GasCosts.FheBitwiseOp[lhs.fheUintType()] +} + +func fheBitOrRequiredGas(environment EVMEnvironment, input []byte) uint64 { + // Implement in terms of bitAnd, because bitwise op costs are currently the same. + return fheBitAndRequiredGas(environment, input) +} + +func fheBitXorRequiredGas(environment EVMEnvironment, input []byte) uint64 { + // Implement in terms of bitAnd, because bitwise op costs are currently the same. + return fheBitAndRequiredGas(environment, input) +} + +func fheRandRequiredGas(environment EVMEnvironment, input []byte) uint64 { + input = input[:minInt(1, len(input))] + + logger := environment.GetLogger() + if len(input) != 1 || !isValidFheType(input[0]) { + logger.Error("fheRand RequiredGas() input len must be at least 1 byte and be a valid FheUint type", "input", hex.EncodeToString(input), "len", len(input)) + return 0 + } + t := FheUintType(input[0]) + return environment.FhevmParams().GasCosts.FheRand[t] +} + +func parseRandUpperBoundInput(input []byte) (randType FheUintType, upperBound *uint256.Int, err error) { + if len(input) != 33 || !isValidFheType(input[32]) { + return FheUint8, nil, fmt.Errorf("parseRandUpperBoundInput() invalid input len or type") + } + randType = FheUintType(input[32]) + upperBound = uint256.NewInt(0) + upperBound.SetBytes32(input) + // For now, we only support bounds of up to 64 bits. + if !upperBound.IsUint64() { + return FheUint8, nil, fmt.Errorf("parseRandUpperBoundInput() only supports bounds up to 64 bits") + } + upperBound64 := upperBound.Uint64() + oneBits := bits.OnesCount64(upperBound64) + if oneBits != 1 { + return FheUint8, nil, fmt.Errorf("parseRandUpperBoundInput() bound not a power of 2: %d", upperBound64) + } + return randType, upperBound, nil +} + +func fheRandBoundedRequiredGas(environment EVMEnvironment, input []byte) uint64 { + input = input[:minInt(33, len(input))] + + logger := environment.GetLogger() + randType, _, err := parseRandUpperBoundInput(input) + if err != nil { + logger.Error("fheRandBounded RequiredGas() bound error", "input", hex.EncodeToString(input), "err", err) + return 0 + } + return environment.FhevmParams().GasCosts.FheRand[randType] +} + +func fheIfThenElseRequiredGas(environment EVMEnvironment, input []byte) uint64 { + input = input[:minInt(96, len(input))] + + logger := environment.GetLogger() + first, second, third, err := get3VerifiedOperands(environment, input) + if err != nil { + logger.Error("IfThenElse op RequiredGas() inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return 0 + } + if first.fheUintType() != FheUint8 { + logger.Error("IfThenElse op RequiredGas() invalid type for condition", "first", first.fheUintType()) + return 0 + } + if second.fheUintType() != third.fheUintType() { + logger.Error("IfThenElse op RequiredGas() operand type mismatch", "second", second.fheUintType(), "third", third.fheUintType()) + return 0 + } + return environment.FhevmParams().GasCosts.FheIfThenElse[second.fheUintType()] +} + +func verifyCiphertextRequiredGas(environment EVMEnvironment, input []byte) uint64 { + if len(input) <= 1 { + environment.GetLogger().Error( + "verifyCiphertext RequiredGas() input needs to contain a ciphertext and one byte for its type", + "len", len(input)) + return 0 + } + ctType := FheUintType(input[len(input)-1]) + return environment.FhevmParams().GasCosts.FheVerify[ctType] +} + +func reencryptRequiredGas(environment EVMEnvironment, input []byte) uint64 { + input = input[:minInt(64, len(input))] + + logger := environment.GetLogger() + if len(input) != 64 { + logger.Error("reencrypt RequiredGas() input len must be 64 bytes", "input", hex.EncodeToString(input), "len", len(input)) + return 0 + } + ct := getVerifiedCiphertext(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 environment.FhevmParams().GasCosts.FheReencrypt[ct.fheUintType()] +} + +func optimisticRequireRequiredGas(environment EVMEnvironment, input []byte) uint64 { + input = input[:minInt(32, len(input))] + + logger := environment.GetLogger() + if len(input) != 32 { + logger.Error("optimisticRequire RequiredGas() input len must be 32 bytes", + "input", hex.EncodeToString(input), "len", len(input)) + return 0 + } + ct := getVerifiedCiphertext(environment, common.BytesToHash(input)) + if ct == nil { + logger.Error("optimisticRequire RequiredGas() input doesn't point to verified ciphertext", + "input", hex.EncodeToString(input)) + return 0 + } + if ct.fheUintType() != FheUint8 { + logger.Error("optimisticRequire RequiredGas() ciphertext type is not FheUint8", + "type", ct.fheUintType()) + return 0 + } + if len(environment.FhevmData().optimisticRequires) == 0 { + return environment.FhevmParams().GasCosts.FheOptRequire[FheUint8] + } + return environment.FhevmParams().GasCosts.FheOptRequireBitAnd[FheUint8] +} + +func castRequiredGas(environment EVMEnvironment, input []byte) uint64 { + input = input[:minInt(33, len(input))] + + if len(input) != 33 { + environment.GetLogger().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 +} + +func decryptRequiredGas(environment EVMEnvironment, input []byte) uint64 { + input = input[:minInt(32, len(input))] + + logger := environment.GetLogger() + if len(input) != 32 { + logger.Error("decrypt RequiredGas() input len must be 32 bytes", "input", hex.EncodeToString(input), "len", len(input)) + return 0 + } + ct := getVerifiedCiphertext(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 environment.FhevmParams().GasCosts.FheDecrypt[ct.fheUintType()] +} + +func fhePubKeyRequiredGas(environment EVMEnvironment, input []byte) uint64 { + return environment.FhevmParams().GasCosts.FhePubKey +} + +func trivialEncryptRequiredGas(environment EVMEnvironment, input []byte) uint64 { + input = input[:minInt(33, len(input))] + + logger := environment.GetLogger() + if len(input) != 33 { + logger.Error("trivialEncrypt RequiredGas() input len must be 33 bytes", "input", hex.EncodeToString(input), "len", len(input)) + return 0 + } + encryptToType := FheUintType(input[32]) + return environment.FhevmParams().GasCosts.FheTrivialEncrypt[encryptToType] +} diff --git a/fhevm/fhelib_run.go b/fhevm/fhelib_run.go new file mode 100644 index 0000000..55ba78f --- /dev/null +++ b/fhevm/fhelib_run.go @@ -0,0 +1,1731 @@ +package fhevm + +import ( + "bytes" + "context" + "encoding/binary" + "encoding/hex" + "errors" + "fmt" + "math/big" + "math/bits" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/holiman/uint256" + fhevm_crypto "github.com/zama-ai/fhevm-go/crypto" + "github.com/zama-ai/fhevm-go/kms" + "golang.org/x/crypto/chacha20" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +func fheAddRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(65, len(input))] + + logger := environment.GetLogger() + + isScalar, err := isScalarOp(input) + if err != nil { + logger.Error("fheAdd can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + if !isScalar { + lhs, rhs, err := get2VerifiedOperands(environment, input) + if err != nil { + logger.Error("fheAdd inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + if lhs.fheUintType() != rhs.fheUintType() { + msg := "fheAdd operand type mismatch" + logger.Error(msg, "lhs", lhs.fheUintType(), "rhs", rhs.fheUintType()) + return nil, errors.New(msg) + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.Add(rhs.ciphertext) + if err != nil { + logger.Error("fheAdd failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheAdd success", "lhs", lhs.hash().Hex(), "rhs", rhs.hash().Hex(), "result", resultHash.Hex()) + return resultHash[:], nil + + } else { + lhs, rhs, err := getScalarOperands(environment, input) + if err != nil { + logger.Error("fheAdd scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.ScalarAdd(rhs.Uint64()) + if err != nil { + logger.Error("fheAdd failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheAdd scalar success", "lhs", lhs.hash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) + return resultHash[:], nil + } +} + +func fheSubRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(65, len(input))] + + logger := environment.GetLogger() + + isScalar, err := isScalarOp(input) + if err != nil { + logger.Error("fheSub can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + if !isScalar { + lhs, rhs, err := get2VerifiedOperands(environment, input) + if err != nil { + logger.Error("fheSub inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + if lhs.fheUintType() != rhs.fheUintType() { + msg := "fheSub operand type mismatch" + logger.Error(msg, "lhs", lhs.fheUintType(), "rhs", rhs.fheUintType()) + return nil, errors.New(msg) + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.Sub(rhs.ciphertext) + if err != nil { + logger.Error("fheSub failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheSub success", "lhs", lhs.hash().Hex(), "rhs", rhs.hash().Hex(), "result", resultHash.Hex()) + return resultHash[:], nil + + } else { + lhs, rhs, err := getScalarOperands(environment, input) + if err != nil { + logger.Error("fheSub scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.ScalarSub(rhs.Uint64()) + if err != nil { + logger.Error("fheSub failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheSub scalar success", "lhs", lhs.hash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) + return resultHash[:], nil + } +} + +func fheMulRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(65, len(input))] + + logger := environment.GetLogger() + + isScalar, err := isScalarOp(input) + if err != nil { + logger.Error("fheMul can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + if !isScalar { + lhs, rhs, err := get2VerifiedOperands(environment, input) + if err != nil { + logger.Error("fheMul inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + if lhs.fheUintType() != rhs.fheUintType() { + msg := "fheMul operand type mismatch" + logger.Error(msg, "lhs", lhs.fheUintType(), "rhs", rhs.fheUintType()) + return nil, errors.New(msg) + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.Mul(rhs.ciphertext) + if err != nil { + logger.Error("fheMul failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheMul success", "lhs", lhs.hash().Hex(), "rhs", rhs.hash().Hex(), "result", resultHash.Hex()) + return resultHash[:], nil + + } else { + lhs, rhs, err := getScalarOperands(environment, input) + if err != nil { + logger.Error("fheMul scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.ScalarMul(rhs.Uint64()) + if err != nil { + logger.Error("fheMul failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheMul scalar success", "lhs", lhs.hash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) + return resultHash[:], nil + } +} + +func fheLeRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(65, len(input))] + + logger := environment.GetLogger() + + isScalar, err := isScalarOp(input) + if err != nil { + logger.Error("fheLe can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + if !isScalar { + lhs, rhs, err := get2VerifiedOperands(environment, input) + if err != nil { + logger.Error("fheLe inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + if lhs.fheUintType() != rhs.fheUintType() { + msg := "fheLe operand type mismatch" + logger.Error(msg, "lhs", lhs.fheUintType(), "rhs", rhs.fheUintType()) + return nil, errors.New(msg) + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.Le(rhs.ciphertext) + if err != nil { + logger.Error("fheLe failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheLe success", "lhs", lhs.hash().Hex(), "rhs", rhs.hash().Hex(), "result", resultHash.Hex()) + return resultHash[:], nil + + } else { + lhs, rhs, err := getScalarOperands(environment, input) + if err != nil { + logger.Error("fheLe scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.ScalarLe(rhs.Uint64()) + if err != nil { + logger.Error("fheLe failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheLe scalar success", "lhs", lhs.hash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) + return resultHash[:], nil + } +} + +func fheLtRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(65, len(input))] + + logger := environment.GetLogger() + + isScalar, err := isScalarOp(input) + if err != nil { + logger.Error("fheLt can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + if !isScalar { + lhs, rhs, err := get2VerifiedOperands(environment, input) + if err != nil { + logger.Error("fheLt inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + if lhs.fheUintType() != rhs.fheUintType() { + msg := "fheLt operand type mismatch" + logger.Error(msg, "lhs", lhs.fheUintType(), "rhs", rhs.fheUintType()) + return nil, errors.New(msg) + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.Lt(rhs.ciphertext) + if err != nil { + logger.Error("fheLt failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheLt success", "lhs", lhs.hash().Hex(), "rhs", rhs.hash().Hex(), "result", resultHash.Hex()) + return resultHash[:], nil + + } else { + lhs, rhs, err := getScalarOperands(environment, input) + if err != nil { + logger.Error("fheLt scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.ScalarLt(rhs.Uint64()) + if err != nil { + logger.Error("fheLt failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheLt scalar success", "lhs", lhs.hash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) + return resultHash[:], nil + } +} + +func fheEqRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(65, len(input))] + + logger := environment.GetLogger() + + isScalar, err := isScalarOp(input) + if err != nil { + logger.Error("fheEq can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + if !isScalar { + lhs, rhs, err := get2VerifiedOperands(environment, input) + if err != nil { + logger.Error("fheEq inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + if lhs.fheUintType() != rhs.fheUintType() { + msg := "fheEq operand type mismatch" + logger.Error(msg, "lhs", lhs.fheUintType(), "rhs", rhs.fheUintType()) + return nil, errors.New(msg) + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.Eq(rhs.ciphertext) + if err != nil { + logger.Error("fheEq failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheEq success", "lhs", lhs.hash().Hex(), "rhs", rhs.hash().Hex(), "result", resultHash.Hex()) + return resultHash[:], nil + + } else { + lhs, rhs, err := getScalarOperands(environment, input) + if err != nil { + logger.Error("fheEq scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.ScalarEq(rhs.Uint64()) + if err != nil { + logger.Error("fheEq failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheEq scalar success", "lhs", lhs.hash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) + return resultHash[:], nil + } +} + +func fheGeRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(65, len(input))] + + logger := environment.GetLogger() + + isScalar, err := isScalarOp(input) + if err != nil { + logger.Error("fheGe can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + if !isScalar { + lhs, rhs, err := get2VerifiedOperands(environment, input) + if err != nil { + logger.Error("fheGe inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + if lhs.fheUintType() != rhs.fheUintType() { + msg := "fheGe operand type mismatch" + logger.Error(msg, "lhs", lhs.fheUintType(), "rhs", rhs.fheUintType()) + return nil, errors.New(msg) + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.Ge(rhs.ciphertext) + if err != nil { + logger.Error("fheGe failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheGe success", "lhs", lhs.hash().Hex(), "rhs", rhs.hash().Hex(), "result", resultHash.Hex()) + return resultHash[:], nil + + } else { + lhs, rhs, err := getScalarOperands(environment, input) + if err != nil { + logger.Error("fheGe scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.ScalarGe(rhs.Uint64()) + if err != nil { + logger.Error("fheGe failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheGe scalar success", "lhs", lhs.hash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) + return resultHash[:], nil + } +} + +func fheGtRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(65, len(input))] + + logger := environment.GetLogger() + + isScalar, err := isScalarOp(input) + if err != nil { + logger.Error("fheGt can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + if !isScalar { + lhs, rhs, err := get2VerifiedOperands(environment, input) + if err != nil { + logger.Error("fheGt inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + if lhs.fheUintType() != rhs.fheUintType() { + msg := "fheGt operand type mismatch" + logger.Error(msg, "lhs", lhs.fheUintType(), "rhs", rhs.fheUintType()) + return nil, errors.New(msg) + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.Gt(rhs.ciphertext) + if err != nil { + logger.Error("fheGt failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheGt success", "lhs", lhs.hash().Hex(), "rhs", rhs.hash().Hex(), "result", resultHash.Hex()) + return resultHash[:], nil + + } else { + lhs, rhs, err := getScalarOperands(environment, input) + if err != nil { + logger.Error("fheGt scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.ScalarGt(rhs.Uint64()) + if err != nil { + logger.Error("fheGt failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheGt scalar success", "lhs", lhs.hash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) + return resultHash[:], nil + } +} + +func fheShlRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(65, len(input))] + + logger := environment.GetLogger() + + isScalar, err := isScalarOp(input) + if err != nil { + logger.Error("fheShl can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + if !isScalar { + lhs, rhs, err := get2VerifiedOperands(environment, input) + if err != nil { + logger.Error("fheShl inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + if lhs.fheUintType() != rhs.fheUintType() { + msg := "fheShl operand type mismatch" + logger.Error(msg, "lhs", lhs.fheUintType(), "rhs", rhs.fheUintType()) + return nil, errors.New(msg) + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.Shl(rhs.ciphertext) + if err != nil { + logger.Error("fheShl failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheShl success", "lhs", lhs.hash().Hex(), "rhs", rhs.hash().Hex(), "result", resultHash.Hex()) + return resultHash[:], nil + + } else { + lhs, rhs, err := getScalarOperands(environment, input) + if err != nil { + logger.Error("fheShl scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.ScalarShl(rhs.Uint64()) + if err != nil { + logger.Error("fheShl failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheShl scalar success", "lhs", lhs.hash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) + return resultHash[:], nil + } +} + +func fheShrRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(65, len(input))] + + logger := environment.GetLogger() + + isScalar, err := isScalarOp(input) + if err != nil { + logger.Error("fheShr can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + if !isScalar { + lhs, rhs, err := get2VerifiedOperands(environment, input) + if err != nil { + logger.Error("fheShr inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + if lhs.fheUintType() != rhs.fheUintType() { + msg := "fheShr operand type mismatch" + logger.Error(msg, "lhs", lhs.fheUintType(), "rhs", rhs.fheUintType()) + return nil, errors.New(msg) + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.Shr(rhs.ciphertext) + if err != nil { + logger.Error("fheShr failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheShr success", "lhs", lhs.hash().Hex(), "rhs", rhs.hash().Hex(), "result", resultHash.Hex()) + return resultHash[:], nil + + } else { + lhs, rhs, err := getScalarOperands(environment, input) + if err != nil { + logger.Error("fheShr scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.ScalarShr(rhs.Uint64()) + if err != nil { + logger.Error("fheShr failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheShr scalar success", "lhs", lhs.hash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) + return resultHash[:], nil + } +} + +func fheNeRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(65, len(input))] + + logger := environment.GetLogger() + + isScalar, err := isScalarOp(input) + if err != nil { + logger.Error("fheNe can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + if !isScalar { + lhs, rhs, err := get2VerifiedOperands(environment, input) + if err != nil { + logger.Error("fheNe inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + if lhs.fheUintType() != rhs.fheUintType() { + msg := "fheNe operand type mismatch" + logger.Error(msg, "lhs", lhs.fheUintType(), "rhs", rhs.fheUintType()) + return nil, errors.New(msg) + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.Ne(rhs.ciphertext) + if err != nil { + logger.Error("fheNe failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheNe success", "lhs", lhs.hash().Hex(), "rhs", rhs.hash().Hex(), "result", resultHash.Hex()) + return resultHash[:], nil + + } else { + lhs, rhs, err := getScalarOperands(environment, input) + if err != nil { + logger.Error("fheNe scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.ScalarNe(rhs.Uint64()) + if err != nil { + logger.Error("fheNe failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheNe scalar success", "lhs", lhs.hash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) + return resultHash[:], nil + } +} + +func fheMinRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(65, len(input))] + + logger := environment.GetLogger() + + isScalar, err := isScalarOp(input) + if err != nil { + logger.Error("fheMin can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + if !isScalar { + lhs, rhs, err := get2VerifiedOperands(environment, input) + if err != nil { + logger.Error("fheMin inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + if lhs.fheUintType() != rhs.fheUintType() { + msg := "fheMin operand type mismatch" + logger.Error(msg, "lhs", lhs.fheUintType(), "rhs", rhs.fheUintType()) + return nil, errors.New(msg) + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.Min(rhs.ciphertext) + if err != nil { + logger.Error("fheMin failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheMin success", "lhs", lhs.hash().Hex(), "rhs", rhs.hash().Hex(), "result", resultHash.Hex()) + return resultHash[:], nil + + } else { + lhs, rhs, err := getScalarOperands(environment, input) + if err != nil { + logger.Error("fheMin scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.ScalarMin(rhs.Uint64()) + if err != nil { + logger.Error("fheMin failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheMin scalar success", "lhs", lhs.hash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) + return resultHash[:], nil + } +} + +func fheMaxRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(65, len(input))] + + logger := environment.GetLogger() + + isScalar, err := isScalarOp(input) + if err != nil { + logger.Error("fheMax can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + if !isScalar { + lhs, rhs, err := get2VerifiedOperands(environment, input) + if err != nil { + logger.Error("fheMax inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + if lhs.fheUintType() != rhs.fheUintType() { + msg := "fheMax operand type mismatch" + logger.Error(msg, "lhs", lhs.fheUintType(), "rhs", rhs.fheUintType()) + return nil, errors.New(msg) + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.Max(rhs.ciphertext) + if err != nil { + logger.Error("fheMax failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheMax success", "lhs", lhs.hash().Hex(), "rhs", rhs.hash().Hex(), "result", resultHash.Hex()) + return resultHash[:], nil + + } else { + lhs, rhs, err := getScalarOperands(environment, input) + if err != nil { + logger.Error("fheMax scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.ScalarMax(rhs.Uint64()) + if err != nil { + logger.Error("fheMax failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheMax scalar success", "lhs", lhs.hash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) + return resultHash[:], nil + } +} + +func fheNegRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(32, len(input))] + + logger := environment.GetLogger() + + if len(input) != 32 { + msg := "fheMax input needs to contain one 256-bit sized value" + logger.Error(msg, "input", hex.EncodeToString(input)) + return nil, errors.New(msg) + + } + + ct := getVerifiedCiphertext(environment, common.BytesToHash(input[0:32])) + if ct == nil { + msg := "fheNeg input not verified" + logger.Error(msg, msg, "input", hex.EncodeToString(input)) + return nil, errors.New(msg) + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, ct.fheUintType()), nil + } + + result, err := ct.ciphertext.Neg() + if err != nil { + logger.Error("fheNeg failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheNeg success", "ct", ct.hash().Hex(), "result", resultHash.Hex()) + return resultHash[:], nil +} + +func fheNotRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(32, len(input))] + + logger := environment.GetLogger() + + if len(input) != 32 { + msg := "fheMax input needs to contain one 256-bit sized value" + logger.Error(msg, "input", hex.EncodeToString(input)) + return nil, errors.New(msg) + + } + + ct := getVerifiedCiphertext(environment, common.BytesToHash(input[0:32])) + if ct == nil { + msg := "fheNot input not verified" + logger.Error(msg, msg, "input", hex.EncodeToString(input)) + return nil, errors.New(msg) + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, ct.fheUintType()), nil + } + + result, err := ct.ciphertext.Not() + if err != nil { + logger.Error("fheNot failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheNot success", "ct", ct.hash().Hex(), "result", resultHash.Hex()) + return resultHash[:], nil +} + +func fheDivRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(65, len(input))] + + logger := environment.GetLogger() + + isScalar, err := isScalarOp(input) + if err != nil { + logger.Error("fheDiv cannot detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + if !isScalar { + err = errors.New("fheDiv supports only scalar input operation, two ciphertexts received") + logger.Error("fheDiv supports only scalar input operation, two ciphertexts received", "input", hex.EncodeToString(input)) + return nil, err + } else { + lhs, rhs, err := getScalarOperands(environment, input) + if err != nil { + logger.Error("fheDiv scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.ScalarDiv(rhs.Uint64()) + if err != nil { + logger.Error("fheDiv failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheDiv scalar success", "lhs", lhs.hash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) + return resultHash[:], nil + } +} + +func fheRemRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(65, len(input))] + + logger := environment.GetLogger() + + isScalar, err := isScalarOp(input) + if err != nil { + logger.Error("fheRem cannot detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + if !isScalar { + err = errors.New("fheRem supports only scalar input operation, two ciphertexts received") + logger.Error("fheRem supports only scalar input operation, two ciphertexts received", "input", hex.EncodeToString(input)) + return nil, err + } else { + lhs, rhs, err := getScalarOperands(environment, input) + if err != nil { + logger.Error("fheRem scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.ScalarRem(rhs.Uint64()) + if err != nil { + logger.Error("fheRem failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheRem scalar success", "lhs", lhs.hash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) + return resultHash[:], nil + } +} + +func fheBitAndRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(65, len(input))] + + logger := environment.GetLogger() + + isScalar, err := isScalarOp(input) + if err != nil { + logger.Error("fheBitAnd can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + if isScalar { + msg := "fheBitAnd scalar op not supported" + logger.Error(msg) + return nil, errors.New(msg) + } + + lhs, rhs, err := get2VerifiedOperands(environment, input) + if err != nil { + logger.Error("fheBitAnd inputs not verified", "err", err) + return nil, err + } + + if lhs.fheUintType() != rhs.fheUintType() { + msg := "fheBitAnd operand type mismatch" + logger.Error(msg, "lhs", lhs.fheUintType(), "rhs", rhs.fheUintType()) + return nil, errors.New(msg) + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.Bitand(rhs.ciphertext) + if err != nil { + logger.Error("fheBitAnd failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheBitAnd success", "lhs", lhs.hash().Hex(), "rhs", rhs.hash().Hex(), "result", resultHash.Hex()) + return resultHash[:], nil +} + +func fheBitOrRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(65, len(input))] + + logger := environment.GetLogger() + + isScalar, err := isScalarOp(input) + if err != nil { + logger.Error("fheBitOr can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + if isScalar { + msg := "fheBitOr scalar op not supported" + logger.Error(msg) + return nil, errors.New(msg) + } + + lhs, rhs, err := get2VerifiedOperands(environment, input) + if err != nil { + logger.Error("fheBitOr inputs not verified", "err", err) + return nil, err + } + + if lhs.fheUintType() != rhs.fheUintType() { + msg := "fheBitOr operand type mismatch" + logger.Error(msg, "lhs", lhs.fheUintType(), "rhs", rhs.fheUintType()) + return nil, errors.New(msg) + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.Bitor(rhs.ciphertext) + if err != nil { + logger.Error("fheBitOr failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheBitOr success", "lhs", lhs.hash().Hex(), "rhs", rhs.hash().Hex(), "result", resultHash.Hex()) + return resultHash[:], nil +} + +func fheBitXorRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(65, len(input))] + + logger := environment.GetLogger() + + isScalar, err := isScalarOp(input) + if err != nil { + logger.Error("fheBitXor can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + if isScalar { + msg := "fheBitXor scalar op not supported" + logger.Error(msg) + return nil, errors.New(msg) + } + + lhs, rhs, err := get2VerifiedOperands(environment, input) + if err != nil { + logger.Error("fheBitXor inputs not verified", "err", err) + return nil, err + } + + if lhs.fheUintType() != rhs.fheUintType() { + msg := "fheBitXor operand type mismatch" + logger.Error(msg, "lhs", lhs.fheUintType(), "rhs", rhs.fheUintType()) + return nil, errors.New(msg) + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, lhs.fheUintType()), nil + } + + result, err := lhs.ciphertext.Bitxor(rhs.ciphertext) + if err != nil { + logger.Error("fheBitXor failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheBitXor success", "lhs", lhs.hash().Hex(), "rhs", rhs.hash().Hex(), "result", resultHash.Hex()) + return resultHash[:], nil +} + +var globalRngSeed []byte + +var rngNonceKey [32]byte = uint256.NewInt(0).Bytes32() + +func init() { + if chacha20.NonceSizeX != 24 { + panic("expected 24 bytes for NonceSizeX") + } + + // TODO: Since the current implementation is not FHE-based and, hence, not private, + // we just initialize the global seed with non-random public data. We will change + // that once the FHE version is available. + globalRngSeed = make([]byte, chacha20.KeySize) + for i := range globalRngSeed { + globalRngSeed[i] = byte(1 + i) + } +} + +// Applies the upperBound (if set) to the rand value and returns the result. +// bitsInRand is the amount of random bits that are contained in rand. +// bitsInRand and upperBound must be powers of 2. +func applyUpperBound(rand uint64, bitsInRand int, upperBound *uint64) uint64 { + if upperBound == nil { + return rand + } else if *upperBound == 0 { + panic("sliceRandom called with upperBound of 0") + } + // Len64() returns the amount of bits needed to represent upperBound. Subtract 1 to get the + // amount of bits requested by the given upperBound as we want to return a value in the [0, upperBound) range. + // Note that upperBound is assumed to be a power of 2. + // + // For example, if upperBound = 128, then bits = 8 - 1 = 7 random bits to be returned. + // To get that amount of random bits from rand, subtract bits from bitsInRand, i.e. + // shift = 32 - 7 = 25. Shifting rand 25 positions would leave 7 of its random bits. + bits := bits.Len64(*upperBound) - 1 + shift := bitsInRand - bits + // If the shift ends up negative or 0, just return rand without any shifts. + if shift <= 0 { + return rand + } + return rand >> shift +} + +func generateRandom(environment EVMEnvironment, caller common.Address, resultType FheUintType, upperBound *uint64) ([]byte, error) { + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() { + return importRandomCiphertext(environment, resultType), nil + } + + // Get the RNG nonce. + protectedStorage := fhevm_crypto.CreateProtectedStorageContractAddress(caller) + currentRngNonceBytes := environment.GetState(protectedStorage, rngNonceKey).Bytes() + + // Increment the RNG nonce by 1. + nextRngNonce := uint256.NewInt(0).SetBytes(currentRngNonceBytes) + nextRngNonce = nextRngNonce.AddUint64(nextRngNonce, 1) + environment.SetState(protectedStorage, rngNonceKey, nextRngNonce.Bytes32()) + + // Compute the seed and use it to create a new cipher. + hasher := crypto.NewKeccakState() + hasher.Write(globalRngSeed) + hasher.Write(caller.Bytes()) + seed := common.Hash{} + _, err := hasher.Read(seed[:]) + if err != nil { + return nil, err + } + // The RNG nonce bytes are of size chacha20.NonceSizeX, which is assumed to be 24 bytes (see init() above). + // Since uint256.Int.z[0] is the least significant byte and since uint256.Int.Bytes32() serializes + // in order of z[3], z[2], z[1], z[0], we want to essentially ignore the first byte, i.e. z[3], because + // it will always be 0 as the nonce size is 24. + cipher, err := chacha20.NewUnauthenticatedCipher(seed.Bytes(), currentRngNonceBytes[32-chacha20.NonceSizeX:32]) + if err != nil { + return nil, err + } + + // XOR a byte array of 0s with the stream from the cipher and receive the result in the same array. + // Apply upperBound, if set. + var randUint uint64 + switch resultType { + case FheUint8: + randBytes := make([]byte, 1) + cipher.XORKeyStream(randBytes, randBytes) + randUint = uint64(randBytes[0]) + randUint = uint64(applyUpperBound(randUint, 8, upperBound)) + case FheUint16: + randBytes := make([]byte, 2) + cipher.XORKeyStream(randBytes, randBytes) + randUint = uint64(binary.BigEndian.Uint16(randBytes)) + randUint = uint64(applyUpperBound(randUint, 16, upperBound)) + case FheUint32: + randBytes := make([]byte, 4) + cipher.XORKeyStream(randBytes, randBytes) + randUint = uint64(binary.BigEndian.Uint32(randBytes)) + randUint = uint64(applyUpperBound(randUint, 32, upperBound)) + case FheUint64: + randBytes := make([]byte, 8) + cipher.XORKeyStream(randBytes, randBytes) + randUint = uint64(binary.BigEndian.Uint64(randBytes)) + randUint = uint64(applyUpperBound(randUint, 64, upperBound)) + default: + return nil, fmt.Errorf("generateRandom() invalid type requested: %d", resultType) + } + + // Trivially encrypt the random integer. + randCt := new(TfheCiphertext) + randBigInt := big.NewInt(0) + randBigInt.SetUint64(randUint) + randCt.TrivialEncrypt(*randBigInt, resultType) + importCiphertext(environment, randCt) + + if err != nil { + return nil, err + } + ctHash := randCt.GetHash() + return ctHash[:], nil +} + +func fheRandRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(1, len(input))] + + logger := environment.GetLogger() + if environment.IsEthCall() { + msg := "fheRand cannot be called via EthCall, because it needs to mutate internal state" + logger.Error(msg) + return nil, errors.New(msg) + } + if len(input) != 1 || !isValidFheType(input[0]) { + msg := "fheRand input len must be at least 1 byte and be a valid FheUint type" + logger.Error(msg, "input", hex.EncodeToString(input), "len", len(input)) + return nil, errors.New(msg) + } + resultType := FheUintType(input[0]) + var noUpperBound *uint64 = nil + return generateRandom(environment, caller, resultType, noUpperBound) +} + +func fheRandBoundedRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(33, len(input))] + + logger := environment.GetLogger() + if environment.IsEthCall() { + msg := "fheRandBoundedRun cannot be called via EthCall, because it needs to mutate internal state" + logger.Error(msg) + return nil, errors.New(msg) + } + randType, bound, err := parseRandUpperBoundInput(input) + if err != nil { + msg := "fheRandBounded bound error" + logger.Error(msg, "input", hex.EncodeToString(input), "err", err) + return nil, errors.New(msg) + } + bound64 := bound.Uint64() + return generateRandom(environment, caller, randType, &bound64) +} + +func fheIfThenElseRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(96, len(input))] + + logger := environment.GetLogger() + first, second, third, err := get3VerifiedOperands(environment, input) + if err != nil { + logger.Error("fheIfThenElse inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + + if second.fheUintType() != third.fheUintType() { + msg := "fheIfThenElse operand type mismatch" + logger.Error(msg, "second", second.fheUintType(), "third", third.fheUintType()) + return nil, errors.New(msg) + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, second.fheUintType()), nil + } + + result, err := first.ciphertext.IfThenElse(second.ciphertext, third.ciphertext) + if err != nil { + logger.Error("fheIfThenElse failed", "err", err) + return nil, err + } + importCiphertext(environment, result) + + resultHash := result.GetHash() + logger.Info("fheIfThenElse success", "first", first.hash().Hex(), "second", second.hash().Hex(), "third", third.hash().Hex(), "result", resultHash.Hex()) + return resultHash[:], nil +} + +func verifyCiphertextRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + logger := environment.GetLogger() + // first 32 bytes of the payload is offset, then 32 bytes are size of byte array + if len(input) <= 68 { + err := errors.New("verifyCiphertext(bytes) must contain at least 68 bytes for selector, byte offset and size") + logger.Error("fheLib precompile error", "err", err, "input", hex.EncodeToString(input)) + return nil, err + } + bytesPaddingSize := 32 + bytesSizeSlotSize := 32 + // read only last 4 bytes of padded number for byte array size + sizeStart := bytesPaddingSize + bytesSizeSlotSize - 4 + sizeEnd := sizeStart + 4 + bytesSize := binary.BigEndian.Uint32(input[sizeStart:sizeEnd]) + bytesStart := bytesPaddingSize + bytesSizeSlotSize + bytesEnd := bytesStart + int(bytesSize) + input = input[bytesStart:minInt(bytesEnd, len(input))] + + if len(input) <= 1 { + msg := "verifyCiphertext Run() input needs to contain a ciphertext and one byte for its type" + logger.Error(msg, "len", len(input)) + return nil, errors.New(msg) + } + + ctBytes := input[:len(input)-1] + ctTypeByte := input[len(input)-1] + if !isValidFheType(ctTypeByte) { + msg := "verifyCiphertext Run() ciphertext type is invalid" + logger.Error(msg, "type", ctTypeByte) + return nil, errors.New(msg) + } + ctType := FheUintType(ctTypeByte) + + expectedSize, found := GetCompactFheCiphertextSize(ctType) + if !found || expectedSize != uint(len(ctBytes)) { + msg := "verifyCiphertext Run() compact ciphertext size is invalid" + logger.Error(msg, "type", ctTypeByte, "size", len(ctBytes), "expectedSize", expectedSize) + return nil, errors.New(msg) + } + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, ctType), nil + } + + ct := new(TfheCiphertext) + err := ct.DeserializeCompact(ctBytes, ctType) + if err != nil { + logger.Error("verifyCiphertext failed to deserialize input ciphertext", + "err", err, + "len", len(ctBytes), + "ctBytes64", hex.EncodeToString(ctBytes[:minInt(len(ctBytes), 64)])) + return nil, err + } + ctHash := ct.GetHash() + importCiphertext(environment, ct) + if environment.IsCommitting() { + logger.Info("verifyCiphertext success", + "ctHash", ctHash.Hex(), + "ctBytes64", hex.EncodeToString(ctBytes[:minInt(len(ctBytes), 64)])) + } + return ctHash.Bytes(), nil +} + +func reencryptRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(64, len(input))] + // precompileBytes, err := reencryptRun(environment, caller, addr, bwCompatBytes, readOnly) + + logger := environment.GetLogger() + if !environment.IsEthCall() { + msg := "reencrypt only supported on EthCall" + logger.Error(msg) + return nil, errors.New(msg) + } + if len(input) != 64 { + msg := "reencrypt input len must be 64 bytes" + logger.Error(msg, "input", hex.EncodeToString(input), "len", len(input)) + return nil, errors.New(msg) + } + ct := getVerifiedCiphertext(environment, common.BytesToHash(input[0:32])) + if ct != nil { + // Make sure we don't decrypt before any optimistic requires are checked. + // optReqResult, optReqErr := evaluateRemainingOptimisticRequires(environment) + // if optReqErr != nil { + // return nil, optReqErr + // } else if !optReqResult { + // return nil, ErrExecutionReverted + // } + + var fheType kms.FheType + switch ct.fheUintType() { + case FheUint8: + fheType = kms.FheType_Euint8 + case FheUint16: + fheType = kms.FheType_Euint16 + case FheUint32: + fheType = kms.FheType_Euint32 + case FheUint64: + fheType = kms.FheType_Euint64 + } + + pubKey := input[32:64] + + // TODO: generate merkle proof for some data + proof := &kms.Proof{ + Height: 3, + MerklePatriciaProof: []byte{}, + } + + reencryptionRequest := &kms.ReencryptionRequest{ + FheType: fheType, + Ciphertext: ct.serialization(), + Request: pubKey, // TODO: change according to the structure of `Request` + Proof: proof, + } + + conn, err := grpc.Dial(kms.KmsEndpointAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + return nil, errors.New("kms unreachable") + } + defer conn.Close() + + ep := kms.NewKmsEndpointClient(conn) + + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + + res, err := ep.Reencrypt(ctx, reencryptionRequest) + if err != nil { + return nil, err + } + + // TODO: decide if `res.Signature` should be verified here + + var reencryptedValue = res.ReencryptedCiphertext + + logger.Info("reencrypt success", "input", hex.EncodeToString(input), "callerAddr", caller, "reencryptedValue", reencryptedValue, "len", len(reencryptedValue)) + reencryptedValue = toEVMBytes(reencryptedValue) + // pad according to abi specification, first add offset to the dynamic bytes argument + outputBytes := make([]byte, 32, len(reencryptedValue)+32) + outputBytes[31] = 0x20 + outputBytes = append(outputBytes, reencryptedValue...) + return padArrayTo32Multiple(outputBytes), nil + } + msg := "reencrypt unverified ciphertext handle" + logger.Error(msg, "input", hex.EncodeToString(input)) + return nil, errors.New(msg) +} + +func optimisticRequireRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(32, len(input))] + + logger := environment.GetLogger() + if len(input) != 32 { + msg := "optimisticRequire input len must be 32 bytes" + logger.Error(msg, "input", hex.EncodeToString(input), "len", len(input)) + return nil, errors.New(msg) + } + ct := getVerifiedCiphertext(environment, common.BytesToHash(input)) + if ct == nil { + msg := "optimisticRequire unverified handle" + logger.Error(msg, "input", hex.EncodeToString(input)) + return nil, errors.New(msg) + } + // If we are doing gas estimation, don't do anything as we would assume all requires are true. + if !environment.IsCommitting() && !environment.IsEthCall() { + return nil, nil + } + if ct.fheUintType() != FheUint8 { + msg := "optimisticRequire ciphertext type is not FheUint8" + logger.Error(msg, "type", ct.fheUintType()) + return nil, errors.New(msg) + } + environment.FhevmData().appendOptimisticRequires(ct.ciphertext) + return nil, nil +} + +func decryptRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(32, len(input))] + + logger := environment.GetLogger() + // if not gas estimation and not view function fail if decryptions are disabled in transactions + if environment.IsCommitting() && !environment.IsEthCall() && environment.FhevmParams().DisableDecryptionsInTransaction { + msg := "decryptions during transaction are disabled" + logger.Error(msg, "input", hex.EncodeToString(input)) + return nil, errors.New(msg) + } + if len(input) != 32 { + msg := "decrypt input len must be 32 bytes" + logger.Error(msg, "input", hex.EncodeToString(input), "len", len(input)) + return nil, errors.New(msg) + } + ct := getVerifiedCiphertext(environment, common.BytesToHash(input)) + if ct == nil { + msg := "decrypt unverified handle" + logger.Error(msg, "input", hex.EncodeToString(input)) + return nil, errors.New(msg) + } + + // If we are doing gas estimation, skip decryption and make sure we return the maximum possible value. + // We need that, because non-zero bytes cost more than zero bytes in some contexts (e.g. SSTORE or memory operations). + if !environment.IsCommitting() && !environment.IsEthCall() { + return bytes.Repeat([]byte{0xFF}, 32), nil + } + // Make sure we don't decrypt before any optimistic requires are checked. + optReqResult, optReqErr := evaluateRemainingOptimisticRequires(environment) + if optReqErr != nil { + return nil, optReqErr + } else if !optReqResult { + return nil, ErrExecutionReverted + } + + plaintext, err := decryptValue(environment, ct.ciphertext) + if err != nil { + logger.Error("decrypt failed", "err", err) + return nil, err + } + + logger.Info("decrypt success", "plaintext", plaintext) + + // Always return a 32-byte big-endian integer. + ret := make([]byte, 32) + bigIntValue := big.NewInt(0) + bigIntValue.SetUint64(plaintext) + bigIntValue.FillBytes(ret) + return ret, nil +} + +func decryptValue(environment EVMEnvironment, ct *TfheCiphertext) (uint64, error) { + + logger := environment.GetLogger() + var fheType kms.FheType + switch ct.Type() { + case FheUint8: + fheType = kms.FheType_Euint8 + case FheUint16: + fheType = kms.FheType_Euint16 + case FheUint32: + fheType = kms.FheType_Euint32 + case FheUint64: + fheType = kms.FheType_Euint64 + } + + // TODO: generate merkle proof for some data + proof := &kms.Proof{ + Height: 4, + MerklePatriciaProof: []byte{}, + } + + decryptionRequest := &kms.DecryptionRequest{ + FheType: fheType, + Ciphertext: ct.Serialize(), + Request: []byte{}, // TODO: change according to the structure of `Request` + Proof: proof, + } + + conn, err := grpc.Dial(kms.KmsEndpointAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + return 0, errors.New("kms unreachable") + } + defer conn.Close() + + ep := kms.NewKmsEndpointClient(conn) + + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + + res, err := ep.Decrypt(ctx, decryptionRequest) + if err != nil { + logger.Error("decrypt failed", "err", err) + return 0, err + } + + return uint64(res.Plaintext), err +} + +// If there are optimistic requires, check them by doing bitwise AND on all of them. +// That works, because we assume their values are either 0 or 1. If there is at least +// one 0, the result will be 0 (false). +func evaluateRemainingOptimisticRequires(environment EVMEnvironment) (bool, error) { + requires := environment.FhevmData().optimisticRequires + len := len(requires) + defer func() { environment.FhevmData().resetOptimisticRequires() }() + if len != 0 { + var cumulative *TfheCiphertext = requires[0] + var err error + for i := 1; i < len; i++ { + cumulative, err = cumulative.Bitand(requires[i]) + if err != nil { + environment.GetLogger().Error("evaluateRemainingOptimisticRequires bitand failed", "err", err) + return false, err + } + } + result, err := decryptValue(environment, cumulative) + return result != 0, err + } + return true, nil +} + +func castRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(33, len(input))] + + logger := environment.GetLogger() + if len(input) != 33 { + msg := "cast Run() input needs to contain a ciphertext and one byte for its type" + logger.Error(msg, "len", len(input)) + return nil, errors.New(msg) + } + + ct := getVerifiedCiphertext(environment, common.BytesToHash(input[0:32])) + if ct == nil { + logger.Error("cast input not verified") + return nil, errors.New("unverified ciphertext handle") + } + + if !isValidFheType(input[32]) { + logger.Error("invalid type to cast to") + return nil, errors.New("invalid type provided") + } + castToType := FheUintType(input[32]) + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return importRandomCiphertext(environment, castToType), nil + } + + res, err := ct.ciphertext.CastTo(castToType) + if err != nil { + msg := "cast Run() error casting ciphertext to" + logger.Error(msg, "type", castToType) + return nil, errors.New(msg) + } + + resHash := res.GetHash() + + importCiphertext(environment, res) + if environment.IsCommitting() { + logger.Info("cast success", + "ctHash", resHash.Hex(), + ) + } + + return resHash.Bytes(), nil +} + +var fhePubKeyHashPrecompile = common.BytesToAddress([]byte{93}) +var fhePubKeyHashSlot = common.Hash{} + +func fhePubKeyRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(1, len(input))] + + existing := environment.GetState(fhePubKeyHashPrecompile, fhePubKeyHashSlot) + if existing != GetPksHash() { + msg := "fhePubKey FHE public key hash doesn't match one stored in state" + environment.GetLogger().Error(msg, "existing", existing.Hex(), "pksHash", GetPksHash().Hex()) + return nil, errors.New(msg) + } + // serialize public key + pksBytes, err := serializePublicKey() + if err != nil { + return nil, err + } + // If we have a single byte with the value of 1, make as an EVM array. + if len(input) == 1 && input[0] == 1 { + pksBytes = toEVMBytes(pksBytes) + } + // pad according to abi specification, first add offset to the dynamic bytes argument + outputBytes := make([]byte, 32, len(pksBytes)+32) + outputBytes[31] = 0x20 + outputBytes = append(outputBytes, pksBytes...) + return padArrayTo32Multiple(outputBytes), nil +} + +func trivialEncryptRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { + input = input[:minInt(33, len(input))] + + logger := environment.GetLogger() + if len(input) != 33 { + msg := "trivialEncrypt input len must be 33 bytes" + logger.Error(msg, "input", hex.EncodeToString(input), "len", len(input)) + return nil, errors.New(msg) + } + + valueToEncrypt := *new(big.Int).SetBytes(input[0:32]) + encryptToType := FheUintType(input[32]) + + ct := new(TfheCiphertext).TrivialEncrypt(valueToEncrypt, encryptToType) + + ctHash := ct.GetHash() + importCiphertext(environment, ct) + if environment.IsCommitting() { + logger.Info("trivialEncrypt success", + "ctHash", ctHash.Hex(), + "valueToEncrypt", valueToEncrypt.Uint64()) + } + return ctHash.Bytes(), nil +} diff --git a/fhevm/instructions.go b/fhevm/instructions.go index 6bb6288..22033ad 100644 --- a/fhevm/instructions.go +++ b/fhevm/instructions.go @@ -173,8 +173,8 @@ func verifyIfCiphertextHandle(handle common.Hash, env EVMEnvironment, contractAd protectedSlotIdx.AddUint64(protectedSlotIdx, 1) } - ct := new(tfheCiphertext) - err := ct.deserialize(ctBytes, metadata.fheUintType) + ct := new(TfheCiphertext) + err := ct.Deserialize(ctBytes, metadata.fheUintType) if err != nil { msg := "opSload failed to deserialize a ciphertext" env.GetLogger().Error(msg, "err", err) @@ -239,7 +239,7 @@ func persistIfVerifiedCiphertext(flagHandleLocation common.Hash, handle common.H } ctPart32 := make([]byte, 32) partIdx := 0 - ctBytes := verifiedCiphertext.ciphertext.serialize() + ctBytes := verifiedCiphertext.ciphertext.Serialize() for i, b := range ctBytes { if i%32 == 0 && i != 0 { env.SetState(protectedStorage, ciphertextSlot.Bytes32(), common.BytesToHash(ctPart32)) @@ -314,7 +314,7 @@ func DelegateCiphertextHandlesInArgs(env EVMEnvironment, args []byte) (verified if contains(args, key.Bytes()) && isVerifiedAtCurrentDepth(env, verifiedCiphertext) { if env.IsCommitting() { env.GetLogger().Info("delegateCiphertextHandlesInArgs", - "handle", verifiedCiphertext.ciphertext.getHash().Hex(), + "handle", verifiedCiphertext.ciphertext.GetHash().Hex(), "fromDepth", env.GetDepth(), "toDepth", env.GetDepth()+1) } @@ -336,7 +336,7 @@ func delegateCiphertextHandlesToCaller(env EVMEnvironment, ret []byte) { if contains(ret, key.Bytes()) && isVerifiedAtCurrentDepth(env, verifiedCiphertext) { if env.IsCommitting() { env.GetLogger().Info("opReturn making ciphertext available to caller", - "handle", verifiedCiphertext.ciphertext.getHash().Hex(), + "handle", verifiedCiphertext.ciphertext.GetHash().Hex(), "fromDepth", env.GetDepth(), "toDepth", env.GetDepth()-1) } @@ -350,7 +350,7 @@ func RemoveVerifiedCipherextsAtCurrentDepth(env EVMEnvironment) { for _, verifiedCiphertext := range env.FhevmData().verifiedCiphertexts { if env.IsCommitting() { env.GetLogger().Info("Run removing ciphertext from depth", - "handle", verifiedCiphertext.ciphertext.getHash().Hex(), + "handle", verifiedCiphertext.ciphertext.GetHash().Hex(), "depth", env.GetDepth()) } // Delete the current EVM depth from the set of verified depths. diff --git a/fhevm/instructions_test.go b/fhevm/instructions_test.go index f281135..0283c0a 100644 --- a/fhevm/instructions_test.go +++ b/fhevm/instructions_test.go @@ -39,18 +39,18 @@ func init() { ) } -func verifyCiphertextInTestMemory(environment EVMEnvironment, value uint64, depth int, t FheUintType) *tfheCiphertext { +func verifyCiphertextInTestMemory(environment EVMEnvironment, value uint64, depth int, t FheUintType) *TfheCiphertext { // Simulate as if the ciphertext is compact and comes externally. ser := encryptAndSerializeCompact(uint64(value), t) - ct := new(tfheCiphertext) - err := ct.deserializeCompact(ser, t) + ct := new(TfheCiphertext) + err := ct.DeserializeCompact(ser, t) if err != nil { panic(err) } return verifyTfheCiphertextInTestMemory(environment, ct, depth) } -func verifyTfheCiphertextInTestMemory(environment EVMEnvironment, ct *tfheCiphertext, depth int) *tfheCiphertext { +func verifyTfheCiphertextInTestMemory(environment EVMEnvironment, ct *TfheCiphertext, depth int) *TfheCiphertext { verifiedCiphertext := importCiphertextToEVMAtDepth(environment, ct, depth) return verifiedCiphertext.ciphertext } @@ -243,7 +243,7 @@ func TestProtectedStorageSstoreSload(t *testing.T) { depth := 1 environment.depth = depth ct := verifyCiphertextInTestMemory(environment, 2, depth, FheUint32) - ctHash := ct.getHash() + ctHash := ct.GetHash() scope := newTestScopeConext() loc := uint256.NewInt(10) value := uint256FromBig(ctHash.Big()) @@ -271,7 +271,7 @@ func TestProtectedStorageSstoreSload(t *testing.T) { if ctAfterSload == nil { t.Fatalf("expected ciphertext is verified after sload") } - if !bytes.Equal(ct.serialize(), ctAfterSload.ciphertext.serialize()) { + if !bytes.Equal(ct.Serialize(), ctAfterSload.ciphertext.Serialize()) { t.Fatalf("expected ciphertext after sload is the same as original") } } @@ -281,7 +281,7 @@ func TestProtectedStorageGarbageCollectionNoFlaggedLocation(t *testing.T) { pc := uint64(0) depth := 1 environment.depth = depth - ctHash := verifyCiphertextInTestMemory(environment, 2, depth, FheUint8).getHash() + ctHash := verifyCiphertextInTestMemory(environment, 2, depth, FheUint8).GetHash() scope := newTestScopeConext() loc := uint256.NewInt(10) locHash := common.BytesToHash(loc.Bytes()) @@ -333,7 +333,7 @@ func TestProtectedStorageGarbageCollection(t *testing.T) { pc := uint64(0) depth := 1 environment.depth = depth - ctHash := verifyCiphertextInTestMemory(environment, 2, depth, FheUint8).getHash() + ctHash := verifyCiphertextInTestMemory(environment, 2, depth, FheUint8).GetHash() scope := newTestScopeConext() loc := uint256.NewInt(10) locHash := common.BytesToHash(loc.Bytes()) @@ -446,7 +446,7 @@ func TestOpReturnDelegation(t *testing.T) { depth := 2 scope := newTestScopeConext() ct := verifyCiphertextInTestMemory(environment, 2, depth, FheUint8) - ctHash := ct.getHash() + ctHash := ct.GetHash() offset := uint256.NewInt(0) length := uint256.NewInt(32) @@ -460,7 +460,7 @@ func TestOpReturnDelegation(t *testing.T) { if ctAfterOp == nil { t.Fatalf("expected ciphertext is still verified after the return op") } - if !bytes.Equal(ct.serialize(), ctAfterOp.ciphertext.serialize()) { + if !bytes.Equal(ct.Serialize(), ctAfterOp.ciphertext.Serialize()) { t.Fatalf("expected ciphertext after the return op is the same as original") } } @@ -470,7 +470,7 @@ func TestOpReturnUnverifyIfNotReturned(t *testing.T) { pc := uint64(0) depth := 2 scope := newTestScopeConext() - ctHash := verifyCiphertextInTestMemory(environment, 2, depth, FheUint8).getHash() + ctHash := verifyCiphertextInTestMemory(environment, 2, depth, FheUint8).GetHash() offset := uint256.NewInt(0) len := uint256.NewInt(32) @@ -492,7 +492,7 @@ func TestOpReturnDoesNotUnverifyIfNotVerified(t *testing.T) { pc := uint64(0) scope := newTestScopeConext() ct := verifyCiphertextInTestMemory(environment, 2, 4, FheUint8) - ctHash := ct.getHash() + ctHash := ct.GetHash() // Return from depth 3 to depth 2. However, ct is not verified at 3 and, hence, cannot // be passed from 3 to 2. However, we expect that ct remains verified at 4. @@ -519,7 +519,7 @@ func TestOpReturnDoesNotUnverifyIfNotVerified(t *testing.T) { if ctAt4 == nil { t.Fatalf("expected ciphertext is still verified at 4") } - if !bytes.Equal(ct.serialize(), ctAt4.ciphertext.serialize()) { + if !bytes.Equal(ct.Serialize(), ctAt4.ciphertext.Serialize()) { t.Fatalf("expected ciphertext after the return op is the same as original") } if ctAt4.verifiedDepths.count() != 1 || !ctAt4.verifiedDepths.has(environment.depth) { diff --git a/fhevm/interface.go b/fhevm/interface.go index fe580ed..baa37d4 100644 --- a/fhevm/interface.go +++ b/fhevm/interface.go @@ -47,14 +47,24 @@ type FhevmData struct { verifiedCiphertexts map[common.Hash]*verifiedCiphertext // All optimistic requires encountered up to that point in the txn execution - optimisticRequires []*tfheCiphertext + optimisticRequires []*TfheCiphertext nextCiphertextHashOnGasEst uint256.Int } +// Set the optimisticRequires array to an empty array +func (data *FhevmData) resetOptimisticRequires() { + data.optimisticRequires = make([]*TfheCiphertext, 0) +} + +// Append one ciphertext to the optimisticRequires array +func (data *FhevmData) appendOptimisticRequires(ct *TfheCiphertext) { + data.optimisticRequires = append(data.optimisticRequires, ct) +} + func NewFhevmData() FhevmData { return FhevmData{ verifiedCiphertexts: make(map[common.Hash]*verifiedCiphertext), - optimisticRequires: make([]*tfheCiphertext, 0), + optimisticRequires: make([]*TfheCiphertext, 0), } } diff --git a/fhevm/interpreter.go b/fhevm/interpreter.go index 8b813e6..5366343 100644 --- a/fhevm/interpreter.go +++ b/fhevm/interpreter.go @@ -47,7 +47,22 @@ func (from *depthSet) clone() (to *depthSet) { type verifiedCiphertext struct { verifiedDepths *depthSet - ciphertext *tfheCiphertext + ciphertext *TfheCiphertext +} + +// Returns the type of the verified ciphertext +func (vc *verifiedCiphertext) fheUintType() FheUintType { + return vc.ciphertext.fheUintType +} + +// Returns the serialization of the verified ciphertext +func (vc *verifiedCiphertext) serialization() []byte { + return vc.ciphertext.serialization +} + +// Returns the hash of the verified ciphertext +func (vc *verifiedCiphertext) hash() common.Hash { + return vc.ciphertext.GetHash() } type PrivilegedMemory struct { @@ -55,12 +70,12 @@ type PrivilegedMemory struct { VerifiedCiphertexts map[common.Hash]*verifiedCiphertext // All optimistic requires encountered up to that point in the txn execution - OptimisticRequires []*tfheCiphertext + optimisticRequires []*TfheCiphertext } var PrivilegedMempory *PrivilegedMemory = &PrivilegedMemory{ make(map[common.Hash]*verifiedCiphertext), - make([]*tfheCiphertext, 0), + make([]*TfheCiphertext, 0), } // Evaluate remaining optimistic requires when Interpreter.Run get an errStopToken diff --git a/fhevm/precompiles.go b/fhevm/precompiles.go index 8a8f824..2af4a29 100644 --- a/fhevm/precompiles.go +++ b/fhevm/precompiles.go @@ -1,68 +1,14 @@ package fhevm import ( - "bytes" - "context" - "crypto/rand" "encoding/binary" "encoding/hex" "errors" - "fmt" - "math/big" - "math/bits" - "time" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/holiman/uint256" - fhevm_crypto "github.com/zama-ai/fhevm-go/crypto" - kms "github.com/zama-ai/fhevm-go/kms" "go.opentelemetry.io/otel" - "golang.org/x/crypto/chacha20" - "golang.org/x/crypto/nacl/box" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" ) -// PrecompiledContract is the basic interface for native Go contracts. The implementation -// requires a deterministic gas count based on the input size of the Run method of the -// contract. -type PrecompiledContract interface { - RequiredGas(environment *EVMEnvironment, input []byte) uint64 // RequiredGas calculates the contract gas use - Run(environment *EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) (ret []byte, err error) -} - -var signatureFheAdd = makeKeccakSignature("fheAdd(uint256,uint256,bytes1)") -var signatureCast = makeKeccakSignature("cast(uint256,bytes1)") -var signatureDecrypt = makeKeccakSignature("decrypt(uint256)") -var signatureFhePubKey = makeKeccakSignature("fhePubKey(bytes1)") -var signatureTrivialEncrypt = makeKeccakSignature("trivialEncrypt(uint256,bytes1)") -var signatureFheSub = makeKeccakSignature("fheSub(uint256,uint256,bytes1)") -var signatureFheMul = makeKeccakSignature("fheMul(uint256,uint256,bytes1)") -var signatureFheLe = makeKeccakSignature("fheLe(uint256,uint256,bytes1)") -var signatureFheLt = makeKeccakSignature("fheLt(uint256,uint256,bytes1)") -var signatureFheEq = makeKeccakSignature("fheEq(uint256,uint256,bytes1)") -var signatureFheGe = makeKeccakSignature("fheGe(uint256,uint256,bytes1)") -var signatureFheGt = makeKeccakSignature("fheGt(uint256,uint256,bytes1)") -var signatureFheShl = makeKeccakSignature("fheShl(uint256,uint256,bytes1)") -var signatureFheShr = makeKeccakSignature("fheShr(uint256,uint256,bytes1)") -var signatureFheNe = makeKeccakSignature("fheNe(uint256,uint256,bytes1)") -var signatureFheMin = makeKeccakSignature("fheMin(uint256,uint256,bytes1)") -var signatureFheMax = makeKeccakSignature("fheMax(uint256,uint256,bytes1)") -var signatureFheNeg = makeKeccakSignature("fheNeg(uint256)") -var signatureFheNot = makeKeccakSignature("fheNot(uint256)") -var signatureFheDiv = makeKeccakSignature("fheDiv(uint256,uint256,bytes1)") -var signatureFheRem = makeKeccakSignature("fheRem(uint256,uint256,bytes1)") -var signatureFheBitAnd = makeKeccakSignature("fheBitAnd(uint256,uint256,bytes1)") -var signatureFheBitOr = makeKeccakSignature("fheBitOr(uint256,uint256,bytes1)") -var signatureFheBitXor = makeKeccakSignature("fheBitXor(uint256,uint256,bytes1)") -var signatureFheRand = makeKeccakSignature("fheRand(bytes1)") -var signatureFheRandBounded = makeKeccakSignature("fheRandBounded(uint256,bytes1)") -var signatureFheIfThenElse = makeKeccakSignature("fheIfThenElse(uint256,uint256,uint256)") -var signatureVerifyCiphertext = makeKeccakSignature("verifyCiphertext(bytes)") -var signatureReencrypt = makeKeccakSignature("reencrypt(uint256,uint256)") -var signatureOptimisticRequire = makeKeccakSignature("optimisticRequire(uint256)") - func FheLibRequiredGas(environment EVMEnvironment, input []byte) uint64 { logger := environment.GetLogger() if len(input) < 4 { @@ -72,2435 +18,40 @@ func FheLibRequiredGas(environment EVMEnvironment, input []byte) uint64 { } // first 4 bytes are for the function signature signature := binary.BigEndian.Uint32(input[0:4]) - switch signature { - case signatureFheAdd: - bwCompatBytes := input[4:minInt(69, len(input))] - return fheAddSubRequiredGas(environment, bwCompatBytes) - case signatureCast: - bwCompatBytes := input[4:minInt(37, len(input))] - return castRequiredGas(environment, bwCompatBytes) - case signatureDecrypt: - bwCompatBytes := input[4:minInt(36, len(input))] - return decryptRequiredGas(environment, bwCompatBytes) - case signatureFhePubKey: - bwCompatBytes := input[4:minInt(5, len(input))] - return fhePubKeyRequiredGas(environment, bwCompatBytes) - case signatureTrivialEncrypt: - bwCompatBytes := input[4:minInt(37, len(input))] - return trivialEncryptRequiredGas(environment, bwCompatBytes) - case signatureFheSub: - bwCompatBytes := input[4:minInt(69, len(input))] - return fheAddSubRequiredGas(environment, bwCompatBytes) - case signatureFheMul: - bwCompatBytes := input[4:minInt(69, len(input))] - return fheMulRequiredGas(environment, bwCompatBytes) - case signatureFheLe: - bwCompatBytes := input[4:minInt(69, len(input))] - return fheLeRequiredGas(environment, bwCompatBytes) - case signatureFheLt: - bwCompatBytes := input[4:minInt(69, len(input))] - return fheLtRequiredGas(environment, bwCompatBytes) - case signatureFheEq: - bwCompatBytes := input[4:minInt(69, len(input))] - return fheEqRequiredGas(environment, bwCompatBytes) - case signatureFheGe: - bwCompatBytes := input[4:minInt(69, len(input))] - return fheGeRequiredGas(environment, bwCompatBytes) - case signatureFheGt: - bwCompatBytes := input[4:minInt(69, len(input))] - return fheGtRequiredGas(environment, bwCompatBytes) - case signatureFheShl: - bwCompatBytes := input[4:minInt(69, len(input))] - return fheShlRequiredGas(environment, bwCompatBytes) - case signatureFheShr: - bwCompatBytes := input[4:minInt(69, len(input))] - return fheShrRequiredGas(environment, bwCompatBytes) - case signatureFheNe: - bwCompatBytes := input[4:minInt(69, len(input))] - return fheNeRequiredGas(environment, bwCompatBytes) - case signatureFheMin: - bwCompatBytes := input[4:minInt(69, len(input))] - return fheMinRequiredGas(environment, bwCompatBytes) - case signatureFheMax: - bwCompatBytes := input[4:minInt(69, len(input))] - return fheMaxRequiredGas(environment, bwCompatBytes) - case signatureFheNeg: - bwCompatBytes := input[4:minInt(36, len(input))] - return fheNegRequiredGas(environment, bwCompatBytes) - case signatureFheNot: - bwCompatBytes := input[4:minInt(36, len(input))] - return fheNotRequiredGas(environment, bwCompatBytes) - case signatureFheDiv: - bwCompatBytes := input[4:minInt(69, len(input))] - return fheDivRequiredGas(environment, bwCompatBytes) - case signatureFheRem: - bwCompatBytes := input[4:minInt(69, len(input))] - return fheRemRequiredGas(environment, bwCompatBytes) - case signatureFheBitAnd: - bwCompatBytes := input[4:minInt(69, len(input))] - return fheBitAndRequiredGas(environment, bwCompatBytes) - case signatureFheBitOr: - bwCompatBytes := input[4:minInt(69, len(input))] - return fheBitOrRequiredGas(environment, bwCompatBytes) - case signatureFheBitXor: - bwCompatBytes := input[4:minInt(69, len(input))] - return fheBitXorRequiredGas(environment, bwCompatBytes) - case signatureFheRand: - bwCompatBytes := input[4:minInt(5, len(input))] - return fheRandRequiredGas(environment, bwCompatBytes) - case signatureFheRandBounded: - bwCompatBytes := input[4:minInt(37, len(input))] - return fheRandBoundedRequiredGas(environment, bwCompatBytes) - case signatureFheIfThenElse: - bwCompatBytes := input[4:minInt(100, len(input))] - return fheIfThenElseRequiredGas(environment, bwCompatBytes) - case signatureVerifyCiphertext: - bwCompatBytes := input[4:] - return verifyCiphertextRequiredGas(environment, bwCompatBytes) - case signatureReencrypt: - bwCompatBytes := input[4:minInt(68, len(input))] - return reencryptRequiredGas(environment, bwCompatBytes) - case signatureOptimisticRequire: - bwCompatBytes := input[4:minInt(36, len(input))] - return optimisticRequireRequiredGas(environment, bwCompatBytes) - default: + + fheLibMethod, found := GetFheLibMethod(signature) + if !found { err := errors.New("precompile method not found") logger.Error("fheLib precompile error", "err", err, "input", hex.EncodeToString(input)) return 0 } + // we remove function signature + input = input[4:] + return fheLibMethod.RequiredGas(environment, input) } -func FheLibRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { +func FheLibRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) (ret []byte, err error) { logger := environment.GetLogger() if len(input) < 4 { err := errors.New("input must contain at least 4 bytes for method signature") logger.Error("fheLib precompile error", "err", err, "input", hex.EncodeToString(input)) return nil, err } - otelCtx := environment.OtelContext() - tracer := otel.Tracer("fhevm") // first 4 bytes are for the function signature signature := binary.BigEndian.Uint32(input[0:4]) - switch signature { - case signatureFheAdd: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fheAdd") - defer span.End() - } - bwCompatBytes := input[4:minInt(69, len(input))] - return fheAddRun(environment, caller, addr, bwCompatBytes, readOnly) - case signatureCast: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fheCast") - defer span.End() - } - bwCompatBytes := input[4:minInt(37, len(input))] - return castRun(environment, caller, addr, bwCompatBytes, readOnly) - case signatureDecrypt: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fheDecrypt") - defer span.End() - } - bwCompatBytes := input[4:minInt(36, len(input))] - return decryptRun(environment, caller, addr, bwCompatBytes, readOnly) - case signatureFhePubKey: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fhePubKey") - defer span.End() - } - bwCompatBytes := input[4:minInt(5, len(input))] - precompileBytes, err := fhePubKeyRun(environment, caller, addr, bwCompatBytes, readOnly) - if err != nil { - return precompileBytes, err - } - // pad according to abi specification, first add offset to the dynamic bytes argument - outputBytes := make([]byte, 32, len(precompileBytes)+32) - outputBytes[31] = 0x20 - outputBytes = append(outputBytes, precompileBytes...) - return padArrayTo32Multiple(outputBytes), nil - case signatureTrivialEncrypt: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fheTrivialEncrypt") - defer span.End() - } - bwCompatBytes := input[4:minInt(37, len(input))] - return trivialEncryptRun(environment, caller, addr, bwCompatBytes, readOnly) - case signatureFheSub: - if otelCtx := environment.OtelContext(); otelCtx != nil { - _, span := otel.Tracer("fhevm").Start(otelCtx, "fheSub") - defer span.End() - } - bwCompatBytes := input[4:minInt(69, len(input))] - return fheSubRun(environment, caller, addr, bwCompatBytes, readOnly) - case signatureFheMul: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fheMul") - defer span.End() - } - bwCompatBytes := input[4:minInt(69, len(input))] - return fheMulRun(environment, caller, addr, bwCompatBytes, readOnly) - case signatureFheLe: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fheLe") - defer span.End() - } - bwCompatBytes := input[4:minInt(69, len(input))] - return fheLeRun(environment, caller, addr, bwCompatBytes, readOnly) - case signatureFheLt: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fheLt") - defer span.End() - } - bwCompatBytes := input[4:minInt(69, len(input))] - return fheLtRun(environment, caller, addr, bwCompatBytes, readOnly) - case signatureFheEq: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fheAdd") - defer span.End() - } - bwCompatBytes := input[4:minInt(69, len(input))] - return fheEqRun(environment, caller, addr, bwCompatBytes, readOnly) - case signatureFheGe: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fheAdd") - defer span.End() - } - bwCompatBytes := input[4:minInt(69, len(input))] - return fheGeRun(environment, caller, addr, bwCompatBytes, readOnly) - case signatureFheGt: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fheAdd") - defer span.End() - } - bwCompatBytes := input[4:minInt(69, len(input))] - return fheGtRun(environment, caller, addr, bwCompatBytes, readOnly) - case signatureFheShl: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fheShl") - defer span.End() - } - bwCompatBytes := input[4:minInt(69, len(input))] - return fheShlRun(environment, caller, addr, bwCompatBytes, readOnly) - case signatureFheShr: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fheShr") - defer span.End() - } - bwCompatBytes := input[4:minInt(69, len(input))] - return fheShrRun(environment, caller, addr, bwCompatBytes, readOnly) - case signatureFheNe: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fheNe") - defer span.End() - } - bwCompatBytes := input[4:minInt(69, len(input))] - return fheNeRun(environment, caller, addr, bwCompatBytes, readOnly) - case signatureFheMin: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fheMin") - defer span.End() - } - bwCompatBytes := input[4:minInt(69, len(input))] - return fheMinRun(environment, caller, addr, bwCompatBytes, readOnly) - case signatureFheMax: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fheMax") - defer span.End() - } - bwCompatBytes := input[4:minInt(69, len(input))] - return fheMaxRun(environment, caller, addr, bwCompatBytes, readOnly) - case signatureFheNeg: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fheNeg") - defer span.End() - } - bwCompatBytes := input[4:minInt(36, len(input))] - return fheNegRun(environment, caller, addr, bwCompatBytes, readOnly) - case signatureFheNot: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fheNot") - defer span.End() - } - bwCompatBytes := input[4:minInt(36, len(input))] - return fheNotRun(environment, caller, addr, bwCompatBytes, readOnly) - case signatureFheDiv: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fheDiv") - defer span.End() - } - bwCompatBytes := input[4:minInt(69, len(input))] - return fheDivRun(environment, caller, addr, bwCompatBytes, readOnly) - case signatureFheRem: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fheRem") - defer span.End() - } - bwCompatBytes := input[4:minInt(69, len(input))] - return fheRemRun(environment, caller, addr, bwCompatBytes, readOnly) - case signatureFheBitAnd: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fheBitAnd") - defer span.End() - } - bwCompatBytes := input[4:minInt(69, len(input))] - return fheBitAndRun(environment, caller, addr, bwCompatBytes, readOnly) - case signatureFheBitOr: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fheBitOr") - defer span.End() - } - bwCompatBytes := input[4:minInt(69, len(input))] - return fheBitOrRun(environment, caller, addr, bwCompatBytes, readOnly) - case signatureFheBitXor: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fheBitXor") - defer span.End() - } - bwCompatBytes := input[4:minInt(69, len(input))] - return fheBitXorRun(environment, caller, addr, bwCompatBytes, readOnly) - case signatureFheRand: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fheRand") - defer span.End() - } - bwCompatBytes := input[4:minInt(5, len(input))] - return fheRandRun(environment, caller, addr, bwCompatBytes, readOnly) - case signatureFheRandBounded: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fheRandBounded") - defer span.End() - } - bwCompatBytes := input[4:minInt(37, len(input))] - return fheRandBoundedRun(environment, caller, addr, bwCompatBytes, readOnly) - case signatureFheIfThenElse: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fheIfThenElse") - defer span.End() - } - bwCompatBytes := input[4:minInt(100, len(input))] - return fheIfThenElseRun(environment, caller, addr, bwCompatBytes, readOnly) - case signatureVerifyCiphertext: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fheVerifyCiphertext") - defer span.End() - } - // first 32 bytes of the payload is offset, then 32 bytes are size of byte array - if len(input) <= 68 { - err := errors.New("verifyCiphertext(bytes) must contain at least 68 bytes for selector, byte offset and size") - logger.Error("fheLib precompile error", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - bytesPaddingSize := 32 - bytesSizeSlotSize := 32 - // read only last 4 bytes of padded number for byte array size - sizeStart := 4 + bytesPaddingSize + bytesSizeSlotSize - 4 - sizeEnd := sizeStart + 4 - bytesSize := binary.BigEndian.Uint32(input[sizeStart:sizeEnd]) - bytesStart := 4 + bytesPaddingSize + bytesSizeSlotSize - bytesEnd := bytesStart + int(bytesSize) - bwCompatBytes := input[bytesStart:minInt(bytesEnd, len(input))] - return verifyCiphertextRun(environment, caller, addr, bwCompatBytes, readOnly) - case signatureReencrypt: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fheReencrypt") - defer span.End() - } - bwCompatBytes := input[4:minInt(68, len(input))] - precompileBytes, err := reencryptRun(environment, caller, addr, bwCompatBytes, readOnly) - if err != nil { - return precompileBytes, err - } - // pad according to abi specification, first add offset to the dynamic bytes argument - outputBytes := make([]byte, 32, len(precompileBytes)+32) - outputBytes[31] = 0x20 - outputBytes = append(outputBytes, precompileBytes...) - return padArrayTo32Multiple(outputBytes), nil - case signatureOptimisticRequire: - if otelCtx != nil { - _, span := tracer.Start(otelCtx, "fheOptimisticRequire") - defer span.End() - } - bwCompatBytes := input[4:minInt(36, len(input))] - return optimisticRequireRun(environment, caller, addr, bwCompatBytes, readOnly) - default: + + fheLibMethod, found := GetFheLibMethod(signature) + if !found { err := errors.New("precompile method not found") logger.Error("fheLib precompile error", "err", err, "input", hex.EncodeToString(input)) return nil, err } -} - -// Gas costs -func fheAddSubRequiredGas(environment EVMEnvironment, input []byte) uint64 { - logger := environment.GetLogger() - isScalar, err := isScalarOp(input) - if err != nil { - logger.Error("fheAdd/Sub RequiredGas() can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) - return 0 - } - var lhs, rhs *verifiedCiphertext - if !isScalar { - lhs, rhs, err = get2VerifiedOperands(environment, input) - if err != nil { - logger.Error("fheAdd/Sub RequiredGas() ciphertext inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return 0 - } - if lhs.ciphertext.fheUintType != rhs.ciphertext.fheUintType { - logger.Error("fheAdd/Sub RequiredGas() operand type mismatch", "lhs", lhs.ciphertext.fheUintType, "rhs", rhs.ciphertext.fheUintType) - return 0 - } - } else { - lhs, _, err = getScalarOperands(environment, input) - if err != nil { - logger.Error("fheAdd/Sub RequiredGas() scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return 0 - } - } - - return environment.FhevmParams().GasCosts.FheAddSub[lhs.ciphertext.fheUintType] -} - -func fheMulRequiredGas(environment EVMEnvironment, input []byte) uint64 { - logger := environment.GetLogger() - isScalar, err := isScalarOp(input) - if err != nil { - logger.Error("fheMul RequiredGas() can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) - return 0 - } - var lhs, rhs *verifiedCiphertext - if !isScalar { - lhs, rhs, err = get2VerifiedOperands(environment, input) - if err != nil { - logger.Error("fheMul RequiredGas() ciphertext inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return 0 - } - if lhs.ciphertext.fheUintType != rhs.ciphertext.fheUintType { - logger.Error("fheMul RequiredGas() operand type mismatch", "lhs", lhs.ciphertext.fheUintType, "rhs", rhs.ciphertext.fheUintType) - return 0 - } - return environment.FhevmParams().GasCosts.FheMul[lhs.ciphertext.fheUintType] - } else { - lhs, _, err = getScalarOperands(environment, input) - if err != nil { - logger.Error("fheMul RequiredGas() scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return 0 - } - return environment.FhevmParams().GasCosts.FheScalarMul[lhs.ciphertext.fheUintType] - } -} - -func fheLeRequiredGas(environment EVMEnvironment, input []byte) uint64 { - logger := environment.GetLogger() - isScalar, err := isScalarOp(input) - if err != nil { - logger.Error("comparison RequiredGas() can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) - return 0 - } - var lhs, rhs *verifiedCiphertext - if !isScalar { - lhs, rhs, err = get2VerifiedOperands(environment, input) - if err != nil { - logger.Error("comparison RequiredGas() ciphertext inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return 0 - } - if lhs.ciphertext.fheUintType != rhs.ciphertext.fheUintType { - logger.Error("comparison RequiredGas() operand type mismatch", "lhs", lhs.ciphertext.fheUintType, "rhs", rhs.ciphertext.fheUintType) - return 0 - } - } else { - lhs, _, err = getScalarOperands(environment, input) - if err != nil { - logger.Error("comparison RequiredGas() scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return 0 - } - } - return environment.FhevmParams().GasCosts.FheLe[lhs.ciphertext.fheUintType] -} - -func fheLtRequiredGas(environment EVMEnvironment, input []byte) uint64 { - // Implement in terms of le, because le and lt costs are currently the same. - return fheLeRequiredGas(environment, input) -} - -func fheEqRequiredGas(environment EVMEnvironment, input []byte) uint64 { - // Implement in terms of le, because comparison costs are currently the same. - return fheLeRequiredGas(environment, input) -} - -func fheGeRequiredGas(environment EVMEnvironment, input []byte) uint64 { - // Implement in terms of le, because comparison costs are currently the same. - return fheLeRequiredGas(environment, input) -} - -func fheGtRequiredGas(environment EVMEnvironment, input []byte) uint64 { - // Implement in terms of le, because comparison costs are currently the same. - return fheLeRequiredGas(environment, input) -} - -func fheNeRequiredGas(environment EVMEnvironment, input []byte) uint64 { - // Implement in terms of le, because comparison costs are currently the same. - return fheLeRequiredGas(environment, input) -} - -func fheShlRequiredGas(environment EVMEnvironment, input []byte) uint64 { - logger := environment.GetLogger() - isScalar, err := isScalarOp(input) - if err != nil { - 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 *verifiedCiphertext - if !isScalar { - lhs, rhs, err = get2VerifiedOperands(environment, input) - if err != nil { - logger.Error("fheShift RequiredGas() ciphertext inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return 0 - } - if lhs.ciphertext.fheUintType != rhs.ciphertext.fheUintType { - logger.Error("fheShift RequiredGas() operand type mismatch", "lhs", lhs.ciphertext.fheUintType, "rhs", rhs.ciphertext.fheUintType) - return 0 - } - return environment.FhevmParams().GasCosts.FheShift[lhs.ciphertext.fheUintType] - } else { - lhs, _, err = getScalarOperands(environment, input) - if err != nil { - logger.Error("fheShift RequiredGas() scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return 0 - } - return environment.FhevmParams().GasCosts.FheScalarShift[lhs.ciphertext.fheUintType] - } -} - -func fheShrRequiredGas(environment EVMEnvironment, input []byte) uint64 { - // Implement in terms of shl, because comparison costs are currently the same. - return fheShlRequiredGas(environment, input) -} - -func fheMinRequiredGas(environment EVMEnvironment, input []byte) uint64 { - logger := environment.GetLogger() - isScalar, err := isScalarOp(input) - if err != nil { - 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 *verifiedCiphertext - if !isScalar { - lhs, rhs, err = get2VerifiedOperands(environment, input) - if err != nil { - logger.Error("fheMin/Max RequiredGas() ciphertext inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return 0 - } - if lhs.ciphertext.fheUintType != rhs.ciphertext.fheUintType { - logger.Error("fheMin/Max RequiredGas() operand type mismatch", "lhs", lhs.ciphertext.fheUintType, "rhs", rhs.ciphertext.fheUintType) - return 0 - } - return environment.FhevmParams().GasCosts.FheMinMax[lhs.ciphertext.fheUintType] - } else { - lhs, _, err = getScalarOperands(environment, input) - if err != nil { - logger.Error("fheMin/Max RequiredGas() scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return 0 - } - return environment.FhevmParams().GasCosts.FheScalarMinMax[lhs.ciphertext.fheUintType] - } -} - -func fheMaxRequiredGas(environment EVMEnvironment, input []byte) uint64 { - // Implement in terms of min, because costs are currently the same. - return fheMinRequiredGas(environment, input) -} - -func fheNegRequiredGas(environment EVMEnvironment, input []byte) uint64 { - logger := environment.GetLogger() - if len(input) != 32 { - logger.Error("fheNeg input needs to contain one 256-bit sized value", "input", hex.EncodeToString(input)) - return 0 - } - ct := getVerifiedCiphertext(environment, common.BytesToHash(input[0:32])) - if ct == nil { - logger.Error("fheNeg input not verified", "input", hex.EncodeToString(input)) - return 0 - } - return environment.FhevmParams().GasCosts.FheNeg[ct.ciphertext.fheUintType] -} - -func fheNotRequiredGas(environment EVMEnvironment, input []byte) uint64 { - // Implement in terms of neg, because costs are currently the same. - logger := environment.GetLogger() - if len(input) != 32 { - logger.Error("fheNot input needs to contain one 256-bit sized value", "input", hex.EncodeToString(input)) - return 0 - } - ct := getVerifiedCiphertext(environment, common.BytesToHash(input[0:32])) - if ct == nil { - logger.Error("fheNot input not verified", "input", hex.EncodeToString(input)) - return 0 - } - return environment.FhevmParams().GasCosts.FheNot[ct.ciphertext.fheUintType] -} - -func fheDivRequiredGas(environment EVMEnvironment, input []byte) uint64 { - logger := environment.GetLogger() - isScalar, err := isScalarOp(input) - if err != nil { - logger.Error("fheDiv RequiredGas() cannot detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) - return 0 - } - var lhs *verifiedCiphertext - if !isScalar { - logger.Error("fheDiv RequiredGas() only scalar in division is supported, two ciphertexts received", "input", hex.EncodeToString(input)) - return 0 - } else { - lhs, _, err = getScalarOperands(environment, input) - if err != nil { - logger.Error("fheDiv RequiredGas() scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return 0 - } - return environment.FhevmParams().GasCosts.FheScalarDiv[lhs.ciphertext.fheUintType] - } -} - -func fheRemRequiredGas(environment EVMEnvironment, input []byte) uint64 { - logger := environment.GetLogger() - isScalar, err := isScalarOp(input) - if err != nil { - logger.Error("fheRem RequiredGas() cannot detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) - return 0 - } - var lhs *verifiedCiphertext - if !isScalar { - logger.Error("fheRem RequiredGas() only scalar in division is supported, two ciphertexts received", "input", hex.EncodeToString(input)) - return 0 - } else { - lhs, _, err = getScalarOperands(environment, input) - if err != nil { - logger.Error("fheRem RequiredGas() scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return 0 - } - return environment.FhevmParams().GasCosts.FheScalarRem[lhs.ciphertext.fheUintType] - } -} - -func fheBitAndRequiredGas(environment EVMEnvironment, input []byte) uint64 { - logger := environment.GetLogger() - - isScalar, err := isScalarOp(input) - if err != nil { - logger.Error("Bitwise op RequiredGas() can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) - return 0 - } - - if isScalar { - msg := "Bitwise op RequiredGas() scalar op not supported" - logger.Error(msg) - return 0 - } - - lhs, rhs, err := get2VerifiedOperands(environment, input) - if err != nil { - logger.Error("Bitwise op RequiredGas() inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return 0 - } - if lhs.ciphertext.fheUintType != rhs.ciphertext.fheUintType { - logger.Error("Bitwise op RequiredGas() operand type mismatch", "lhs", lhs.ciphertext.fheUintType, "rhs", rhs.ciphertext.fheUintType) - return 0 - } - return environment.FhevmParams().GasCosts.FheBitwiseOp[lhs.ciphertext.fheUintType] -} - -func fheBitOrRequiredGas(environment EVMEnvironment, input []byte) uint64 { - // Implement in terms of bitAnd, because bitwise op costs are currently the same. - return fheBitAndRequiredGas(environment, input) -} - -func fheBitXorRequiredGas(environment EVMEnvironment, input []byte) uint64 { - // Implement in terms of bitAnd, because bitwise op costs are currently the same. - return fheBitAndRequiredGas(environment, input) -} - -func fheRandRequiredGas(environment EVMEnvironment, input []byte) uint64 { - logger := environment.GetLogger() - if len(input) != 1 || !isValidType(input[0]) { - logger.Error("fheRand RequiredGas() input len must be at least 1 byte and be a valid FheUint type", "input", hex.EncodeToString(input), "len", len(input)) - return 0 - } - t := FheUintType(input[0]) - return environment.FhevmParams().GasCosts.FheRand[t] -} - -func parseRandUpperBoundInput(input []byte) (randType FheUintType, upperBound *uint256.Int, err error) { - if len(input) != 33 || !isValidType(input[32]) { - return FheUint8, nil, fmt.Errorf("parseRandUpperBoundInput() invalid input len or type") - } - randType = FheUintType(input[32]) - upperBound = uint256.NewInt(0) - upperBound.SetBytes32(input) - // For now, we only support bounds of up to 64 bits. - if !upperBound.IsUint64() { - return FheUint8, nil, fmt.Errorf("parseRandUpperBoundInput() only supports bounds up to 64 bits") - } - upperBound64 := upperBound.Uint64() - oneBits := bits.OnesCount64(upperBound64) - if oneBits != 1 { - return FheUint8, nil, fmt.Errorf("parseRandUpperBoundInput() bound not a power of 2: %d", upperBound64) - } - return randType, upperBound, nil -} - -func fheRandBoundedRequiredGas(environment EVMEnvironment, input []byte) uint64 { - logger := environment.GetLogger() - randType, _, err := parseRandUpperBoundInput(input) - if err != nil { - logger.Error("fheRandBounded RequiredGas() bound error", "input", hex.EncodeToString(input), "err", err) - return 0 - } - return environment.FhevmParams().GasCosts.FheRand[randType] -} - -func fheIfThenElseRequiredGas(environment EVMEnvironment, input []byte) uint64 { - logger := environment.GetLogger() - first, second, third, err := get3VerifiedOperands(environment, input) - if err != nil { - logger.Error("IfThenElse op RequiredGas() inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return 0 - } - if first.ciphertext.fheUintType != FheUint8 { - logger.Error("IfThenElse op RequiredGas() invalid type for condition", "first", first.ciphertext.fheUintType) - return 0 - } - if second.ciphertext.fheUintType != third.ciphertext.fheUintType { - logger.Error("IfThenElse op RequiredGas() operand type mismatch", "second", second.ciphertext.fheUintType, "third", third.ciphertext.fheUintType) - return 0 - } - return environment.FhevmParams().GasCosts.FheIfThenElse[second.ciphertext.fheUintType] -} - -func verifyCiphertextRequiredGas(environment EVMEnvironment, input []byte) uint64 { - if len(input) <= 1 { - environment.GetLogger().Error( - "verifyCiphertext RequiredGas() input needs to contain a ciphertext and one byte for its type", - "len", len(input)) - return 0 - } - ctType := FheUintType(input[len(input)-1]) - return environment.FhevmParams().GasCosts.FheVerify[ctType] -} - -func reencryptRequiredGas(environment EVMEnvironment, input []byte) uint64 { - logger := environment.GetLogger() - if len(input) != 64 { - logger.Error("reencrypt RequiredGas() input len must be 64 bytes", "input", hex.EncodeToString(input), "len", len(input)) - return 0 - } - ct := getVerifiedCiphertext(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 environment.FhevmParams().GasCosts.FheReencrypt[ct.ciphertext.fheUintType] -} - -func optimisticRequireRequiredGas(environment EVMEnvironment, input []byte) uint64 { - logger := environment.GetLogger() - if len(input) != 32 { - logger.Error("optimisticRequire RequiredGas() input len must be 32 bytes", - "input", hex.EncodeToString(input), "len", len(input)) - return 0 - } - ct := getVerifiedCiphertext(environment, common.BytesToHash(input)) - if ct == nil { - logger.Error("optimisticRequire RequiredGas() input doesn't point to verified ciphertext", - "input", hex.EncodeToString(input)) - return 0 - } - if ct.ciphertext.fheUintType != FheUint8 { - logger.Error("optimisticRequire RequiredGas() ciphertext type is not FheUint8", - "type", ct.ciphertext.fheUintType) - return 0 - } - if len(environment.FhevmData().optimisticRequires) == 0 { - return environment.FhevmParams().GasCosts.FheOptRequire[FheUint8] - } - return environment.FhevmParams().GasCosts.FheOptRequireBitAnd[FheUint8] -} - -func castRequiredGas(environment EVMEnvironment, input []byte) uint64 { - if len(input) != 33 { - environment.GetLogger().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 -} - -func decryptRequiredGas(environment EVMEnvironment, input []byte) uint64 { - logger := environment.GetLogger() - if len(input) != 32 { - logger.Error("decrypt RequiredGas() input len must be 32 bytes", "input", hex.EncodeToString(input), "len", len(input)) - return 0 - } - ct := getVerifiedCiphertext(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 environment.FhevmParams().GasCosts.FheDecrypt[ct.ciphertext.fheUintType] -} - -func fhePubKeyRequiredGas(environment EVMEnvironment, input []byte) uint64 { - return environment.FhevmParams().GasCosts.FhePubKey -} - -func trivialEncryptRequiredGas(environment EVMEnvironment, input []byte) uint64 { - logger := environment.GetLogger() - if len(input) != 33 { - logger.Error("trivialEncrypt RequiredGas() input len must be 33 bytes", "input", hex.EncodeToString(input), "len", len(input)) - return 0 - } - encryptToType := FheUintType(input[32]) - return environment.FhevmParams().GasCosts.FheTrivialEncrypt[encryptToType] -} - -// Implementations -func fheAddRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - - isScalar, err := isScalarOp(input) - if err != nil { - logger.Error("fheAdd can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - if !isScalar { - lhs, rhs, err := get2VerifiedOperands(environment, input) - if err != nil { - logger.Error("fheAdd inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - if lhs.ciphertext.fheUintType != rhs.ciphertext.fheUintType { - msg := "fheAdd operand type mismatch" - logger.Error(msg, "lhs", lhs.ciphertext.fheUintType, "rhs", rhs.ciphertext.fheUintType) - return nil, errors.New(msg) - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.add(rhs.ciphertext) - if err != nil { - logger.Error("fheAdd failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheAdd success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.ciphertext.getHash().Hex(), "result", resultHash.Hex()) - return resultHash[:], nil - - } else { - lhs, rhs, err := getScalarOperands(environment, input) - if err != nil { - logger.Error("fheAdd scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.scalarAdd(rhs.Uint64()) - if err != nil { - logger.Error("fheAdd failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheAdd scalar success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) - return resultHash[:], nil - } -} - -func fheSubRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - - isScalar, err := isScalarOp(input) - if err != nil { - logger.Error("fheSub can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - if !isScalar { - lhs, rhs, err := get2VerifiedOperands(environment, input) - if err != nil { - logger.Error("fheSub inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - if lhs.ciphertext.fheUintType != rhs.ciphertext.fheUintType { - msg := "fheSub operand type mismatch" - logger.Error(msg, "lhs", lhs.ciphertext.fheUintType, "rhs", rhs.ciphertext.fheUintType) - return nil, errors.New(msg) - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.sub(rhs.ciphertext) - if err != nil { - logger.Error("fheSub failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheSub success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.ciphertext.getHash().Hex(), "result", resultHash.Hex()) - return resultHash[:], nil - - } else { - lhs, rhs, err := getScalarOperands(environment, input) - if err != nil { - logger.Error("fheSub scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.scalarSub(rhs.Uint64()) - if err != nil { - logger.Error("fheSub failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheSub scalar success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) - return resultHash[:], nil - } -} - -func fheMulRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - - isScalar, err := isScalarOp(input) - if err != nil { - logger.Error("fheMul can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - if !isScalar { - lhs, rhs, err := get2VerifiedOperands(environment, input) - if err != nil { - logger.Error("fheMul inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - if lhs.ciphertext.fheUintType != rhs.ciphertext.fheUintType { - msg := "fheMul operand type mismatch" - logger.Error(msg, "lhs", lhs.ciphertext.fheUintType, "rhs", rhs.ciphertext.fheUintType) - return nil, errors.New(msg) - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.mul(rhs.ciphertext) - if err != nil { - logger.Error("fheMul failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheMul success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.ciphertext.getHash().Hex(), "result", resultHash.Hex()) - return resultHash[:], nil - - } else { - lhs, rhs, err := getScalarOperands(environment, input) - if err != nil { - logger.Error("fheMul scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.scalarMul(rhs.Uint64()) - if err != nil { - logger.Error("fheMul failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheMul scalar success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) - return resultHash[:], nil - } -} - -func fheLeRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - - isScalar, err := isScalarOp(input) - if err != nil { - logger.Error("fheLe can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - if !isScalar { - lhs, rhs, err := get2VerifiedOperands(environment, input) - if err != nil { - logger.Error("fheLe inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - if lhs.ciphertext.fheUintType != rhs.ciphertext.fheUintType { - msg := "fheLe operand type mismatch" - logger.Error(msg, "lhs", lhs.ciphertext.fheUintType, "rhs", rhs.ciphertext.fheUintType) - return nil, errors.New(msg) - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.le(rhs.ciphertext) - if err != nil { - logger.Error("fheLe failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheLe success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.ciphertext.getHash().Hex(), "result", resultHash.Hex()) - return resultHash[:], nil - - } else { - lhs, rhs, err := getScalarOperands(environment, input) - if err != nil { - logger.Error("fheLe scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.scalarLe(rhs.Uint64()) - if err != nil { - logger.Error("fheLe failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheLe scalar success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) - return resultHash[:], nil - } -} - -func fheLtRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - - isScalar, err := isScalarOp(input) - if err != nil { - logger.Error("fheLt can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - if !isScalar { - lhs, rhs, err := get2VerifiedOperands(environment, input) - if err != nil { - logger.Error("fheLt inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - if lhs.ciphertext.fheUintType != rhs.ciphertext.fheUintType { - msg := "fheLt operand type mismatch" - logger.Error(msg, "lhs", lhs.ciphertext.fheUintType, "rhs", rhs.ciphertext.fheUintType) - return nil, errors.New(msg) - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.lt(rhs.ciphertext) - if err != nil { - logger.Error("fheLt failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheLt success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.ciphertext.getHash().Hex(), "result", resultHash.Hex()) - return resultHash[:], nil - - } else { - lhs, rhs, err := getScalarOperands(environment, input) - if err != nil { - logger.Error("fheLt scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.scalarLt(rhs.Uint64()) - if err != nil { - logger.Error("fheLt failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheLt scalar success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) - return resultHash[:], nil - } -} - -func fheEqRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - - isScalar, err := isScalarOp(input) - if err != nil { - logger.Error("fheEq can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - if !isScalar { - lhs, rhs, err := get2VerifiedOperands(environment, input) - if err != nil { - logger.Error("fheEq inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - if lhs.ciphertext.fheUintType != rhs.ciphertext.fheUintType { - msg := "fheEq operand type mismatch" - logger.Error(msg, "lhs", lhs.ciphertext.fheUintType, "rhs", rhs.ciphertext.fheUintType) - return nil, errors.New(msg) - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.eq(rhs.ciphertext) - if err != nil { - logger.Error("fheEq failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheEq success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.ciphertext.getHash().Hex(), "result", resultHash.Hex()) - return resultHash[:], nil - - } else { - lhs, rhs, err := getScalarOperands(environment, input) - if err != nil { - logger.Error("fheEq scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.scalarEq(rhs.Uint64()) - if err != nil { - logger.Error("fheEq failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheEq scalar success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) - return resultHash[:], nil - } -} - -func fheGeRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - - isScalar, err := isScalarOp(input) - if err != nil { - logger.Error("fheGe can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - if !isScalar { - lhs, rhs, err := get2VerifiedOperands(environment, input) - if err != nil { - logger.Error("fheGe inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - if lhs.ciphertext.fheUintType != rhs.ciphertext.fheUintType { - msg := "fheGe operand type mismatch" - logger.Error(msg, "lhs", lhs.ciphertext.fheUintType, "rhs", rhs.ciphertext.fheUintType) - return nil, errors.New(msg) - } + // remove function signature + input = input[4:] + // trace function execution + _, span := otel.Tracer("fhevm").Start(environment.OtelContext(), fheLibMethod.name) + ret, err = fheLibMethod.Run(environment, caller, addr, input, readOnly) + span.End() - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.ge(rhs.ciphertext) - if err != nil { - logger.Error("fheGe failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheGe success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.ciphertext.getHash().Hex(), "result", resultHash.Hex()) - return resultHash[:], nil - - } else { - lhs, rhs, err := getScalarOperands(environment, input) - if err != nil { - logger.Error("fheGe scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.scalarGe(rhs.Uint64()) - if err != nil { - logger.Error("fheGe failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheGe scalar success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) - return resultHash[:], nil - } -} - -func fheGtRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - - isScalar, err := isScalarOp(input) - if err != nil { - logger.Error("fheGt can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - if !isScalar { - lhs, rhs, err := get2VerifiedOperands(environment, input) - if err != nil { - logger.Error("fheGt inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - if lhs.ciphertext.fheUintType != rhs.ciphertext.fheUintType { - msg := "fheGt operand type mismatch" - logger.Error(msg, "lhs", lhs.ciphertext.fheUintType, "rhs", rhs.ciphertext.fheUintType) - return nil, errors.New(msg) - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.gt(rhs.ciphertext) - if err != nil { - logger.Error("fheGt failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheGt success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.ciphertext.getHash().Hex(), "result", resultHash.Hex()) - return resultHash[:], nil - - } else { - lhs, rhs, err := getScalarOperands(environment, input) - if err != nil { - logger.Error("fheGt scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.scalarGt(rhs.Uint64()) - if err != nil { - logger.Error("fheGt failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheGt scalar success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) - return resultHash[:], nil - } -} - -func fheShlRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - - isScalar, err := isScalarOp(input) - if err != nil { - logger.Error("fheShl can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - if !isScalar { - lhs, rhs, err := get2VerifiedOperands(environment, input) - if err != nil { - logger.Error("fheShl inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - if lhs.ciphertext.fheUintType != rhs.ciphertext.fheUintType { - msg := "fheShl operand type mismatch" - logger.Error(msg, "lhs", lhs.ciphertext.fheUintType, "rhs", rhs.ciphertext.fheUintType) - return nil, errors.New(msg) - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.shl(rhs.ciphertext) - if err != nil { - logger.Error("fheShl failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheShl success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.ciphertext.getHash().Hex(), "result", resultHash.Hex()) - return resultHash[:], nil - - } else { - lhs, rhs, err := getScalarOperands(environment, input) - if err != nil { - logger.Error("fheShl scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.scalarShl(rhs.Uint64()) - if err != nil { - logger.Error("fheShl failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheShl scalar success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) - return resultHash[:], nil - } -} - -func fheShrRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - - isScalar, err := isScalarOp(input) - if err != nil { - logger.Error("fheShr can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - if !isScalar { - lhs, rhs, err := get2VerifiedOperands(environment, input) - if err != nil { - logger.Error("fheShr inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - if lhs.ciphertext.fheUintType != rhs.ciphertext.fheUintType { - msg := "fheShr operand type mismatch" - logger.Error(msg, "lhs", lhs.ciphertext.fheUintType, "rhs", rhs.ciphertext.fheUintType) - return nil, errors.New(msg) - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.shr(rhs.ciphertext) - if err != nil { - logger.Error("fheShr failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheShr success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.ciphertext.getHash().Hex(), "result", resultHash.Hex()) - return resultHash[:], nil - - } else { - lhs, rhs, err := getScalarOperands(environment, input) - if err != nil { - logger.Error("fheShr scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.scalarShr(rhs.Uint64()) - if err != nil { - logger.Error("fheShr failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheShr scalar success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) - return resultHash[:], nil - } -} - -func fheNeRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - - isScalar, err := isScalarOp(input) - if err != nil { - logger.Error("fheNe can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - if !isScalar { - lhs, rhs, err := get2VerifiedOperands(environment, input) - if err != nil { - logger.Error("fheNe inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - if lhs.ciphertext.fheUintType != rhs.ciphertext.fheUintType { - msg := "fheNe operand type mismatch" - logger.Error(msg, "lhs", lhs.ciphertext.fheUintType, "rhs", rhs.ciphertext.fheUintType) - return nil, errors.New(msg) - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.ne(rhs.ciphertext) - if err != nil { - logger.Error("fheNe failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheNe success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.ciphertext.getHash().Hex(), "result", resultHash.Hex()) - return resultHash[:], nil - - } else { - lhs, rhs, err := getScalarOperands(environment, input) - if err != nil { - logger.Error("fheNe scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.scalarNe(rhs.Uint64()) - if err != nil { - logger.Error("fheNe failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheNe scalar success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) - return resultHash[:], nil - } -} - -func fheMinRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - - isScalar, err := isScalarOp(input) - if err != nil { - logger.Error("fheMin can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - if !isScalar { - lhs, rhs, err := get2VerifiedOperands(environment, input) - if err != nil { - logger.Error("fheMin inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - if lhs.ciphertext.fheUintType != rhs.ciphertext.fheUintType { - msg := "fheMin operand type mismatch" - logger.Error(msg, "lhs", lhs.ciphertext.fheUintType, "rhs", rhs.ciphertext.fheUintType) - return nil, errors.New(msg) - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.min(rhs.ciphertext) - if err != nil { - logger.Error("fheMin failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheMin success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.ciphertext.getHash().Hex(), "result", resultHash.Hex()) - return resultHash[:], nil - - } else { - lhs, rhs, err := getScalarOperands(environment, input) - if err != nil { - logger.Error("fheMin scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.scalarMin(rhs.Uint64()) - if err != nil { - logger.Error("fheMin failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheMin scalar success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) - return resultHash[:], nil - } -} - -func fheMaxRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - - isScalar, err := isScalarOp(input) - if err != nil { - logger.Error("fheMax can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - if !isScalar { - lhs, rhs, err := get2VerifiedOperands(environment, input) - if err != nil { - logger.Error("fheMax inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - if lhs.ciphertext.fheUintType != rhs.ciphertext.fheUintType { - msg := "fheMax operand type mismatch" - logger.Error(msg, "lhs", lhs.ciphertext.fheUintType, "rhs", rhs.ciphertext.fheUintType) - return nil, errors.New(msg) - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.max(rhs.ciphertext) - if err != nil { - logger.Error("fheMax failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheMax success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.ciphertext.getHash().Hex(), "result", resultHash.Hex()) - return resultHash[:], nil - - } else { - lhs, rhs, err := getScalarOperands(environment, input) - if err != nil { - logger.Error("fheMax scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.scalarMax(rhs.Uint64()) - if err != nil { - logger.Error("fheMax failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheMax scalar success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) - return resultHash[:], nil - } -} - -func fheNegRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - - if len(input) != 32 { - msg := "fheMax input needs to contain one 256-bit sized value" - logger.Error(msg, "input", hex.EncodeToString(input)) - return nil, errors.New(msg) - - } - - ct := getVerifiedCiphertext(environment, common.BytesToHash(input[0:32])) - if ct == nil { - msg := "fheNeg input not verified" - logger.Error(msg, msg, "input", hex.EncodeToString(input)) - return nil, errors.New(msg) - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, ct.ciphertext.fheUintType), nil - } - - result, err := ct.ciphertext.neg() - if err != nil { - logger.Error("fheNeg failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheNeg success", "ct", ct.ciphertext.getHash().Hex(), "result", resultHash.Hex()) - return resultHash[:], nil -} - -func fheNotRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - - if len(input) != 32 { - msg := "fheMax input needs to contain one 256-bit sized value" - logger.Error(msg, "input", hex.EncodeToString(input)) - return nil, errors.New(msg) - - } - - ct := getVerifiedCiphertext(environment, common.BytesToHash(input[0:32])) - if ct == nil { - msg := "fheNot input not verified" - logger.Error(msg, msg, "input", hex.EncodeToString(input)) - return nil, errors.New(msg) - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, ct.ciphertext.fheUintType), nil - } - - result, err := ct.ciphertext.not() - if err != nil { - logger.Error("fheNot failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheNot success", "ct", ct.ciphertext.getHash().Hex(), "result", resultHash.Hex()) - return resultHash[:], nil -} - -func fheDivRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - - isScalar, err := isScalarOp(input) - if err != nil { - logger.Error("fheDiv cannot detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - if !isScalar { - err = errors.New("fheDiv supports only scalar input operation, two ciphertexts received") - logger.Error("fheDiv supports only scalar input operation, two ciphertexts received", "input", hex.EncodeToString(input)) - return nil, err - } else { - lhs, rhs, err := getScalarOperands(environment, input) - if err != nil { - logger.Error("fheDiv scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.scalarDiv(rhs.Uint64()) - if err != nil { - logger.Error("fheDiv failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheDiv scalar success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) - return resultHash[:], nil - } -} - -func fheRemRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - - isScalar, err := isScalarOp(input) - if err != nil { - logger.Error("fheRem cannot detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - if !isScalar { - err = errors.New("fheRem supports only scalar input operation, two ciphertexts received") - logger.Error("fheRem supports only scalar input operation, two ciphertexts received", "input", hex.EncodeToString(input)) - return nil, err - } else { - lhs, rhs, err := getScalarOperands(environment, input) - if err != nil { - logger.Error("fheRem scalar inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.scalarRem(rhs.Uint64()) - if err != nil { - logger.Error("fheRem failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheRem scalar success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) - return resultHash[:], nil - } -} - -func fheBitAndRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - - isScalar, err := isScalarOp(input) - if err != nil { - logger.Error("fheBitAnd can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - if isScalar { - msg := "fheBitAnd scalar op not supported" - logger.Error(msg) - return nil, errors.New(msg) - } - - lhs, rhs, err := get2VerifiedOperands(environment, input) - if err != nil { - logger.Error("fheBitAnd inputs not verified", "err", err) - return nil, err - } - - if lhs.ciphertext.fheUintType != rhs.ciphertext.fheUintType { - msg := "fheBitAnd operand type mismatch" - logger.Error(msg, "lhs", lhs.ciphertext.fheUintType, "rhs", rhs.ciphertext.fheUintType) - return nil, errors.New(msg) - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.bitand(rhs.ciphertext) - if err != nil { - logger.Error("fheBitAnd failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheBitAnd success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.ciphertext.getHash().Hex(), "result", resultHash.Hex()) - return resultHash[:], nil -} - -func fheBitOrRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - - isScalar, err := isScalarOp(input) - if err != nil { - logger.Error("fheBitOr can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - if isScalar { - msg := "fheBitOr scalar op not supported" - logger.Error(msg) - return nil, errors.New(msg) - } - - lhs, rhs, err := get2VerifiedOperands(environment, input) - if err != nil { - logger.Error("fheBitOr inputs not verified", "err", err) - return nil, err - } - - if lhs.ciphertext.fheUintType != rhs.ciphertext.fheUintType { - msg := "fheBitOr operand type mismatch" - logger.Error(msg, "lhs", lhs.ciphertext.fheUintType, "rhs", rhs.ciphertext.fheUintType) - return nil, errors.New(msg) - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.bitor(rhs.ciphertext) - if err != nil { - logger.Error("fheBitOr failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheBitOr success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.ciphertext.getHash().Hex(), "result", resultHash.Hex()) - return resultHash[:], nil -} - -func fheBitXorRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - - isScalar, err := isScalarOp(input) - if err != nil { - logger.Error("fheBitXor can not detect if operator is meant to be scalar", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - if isScalar { - msg := "fheBitXor scalar op not supported" - logger.Error(msg) - return nil, errors.New(msg) - } - - lhs, rhs, err := get2VerifiedOperands(environment, input) - if err != nil { - logger.Error("fheBitXor inputs not verified", "err", err) - return nil, err - } - - if lhs.ciphertext.fheUintType != rhs.ciphertext.fheUintType { - msg := "fheBitXor operand type mismatch" - logger.Error(msg, "lhs", lhs.ciphertext.fheUintType, "rhs", rhs.ciphertext.fheUintType) - return nil, errors.New(msg) - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, lhs.ciphertext.fheUintType), nil - } - - result, err := lhs.ciphertext.bitxor(rhs.ciphertext) - if err != nil { - logger.Error("fheBitXor failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheBitXor success", "lhs", lhs.ciphertext.getHash().Hex(), "rhs", rhs.ciphertext.getHash().Hex(), "result", resultHash.Hex()) - return resultHash[:], nil -} - -var globalRngSeed []byte - -var rngNonceKey [32]byte = uint256.NewInt(0).Bytes32() - -func init() { - if chacha20.NonceSizeX != 24 { - panic("expected 24 bytes for NonceSizeX") - } - - // TODO: Since the current implementation is not FHE-based and, hence, not private, - // we just initialize the global seed with non-random public data. We will change - // that once the FHE version is available. - globalRngSeed = make([]byte, chacha20.KeySize) - for i := range globalRngSeed { - globalRngSeed[i] = byte(1 + i) - } -} - -// Applies the upperBound (if set) to the rand value and returns the result. -// bitsInRand is the amount of random bits that are contained in rand. -// bitsInRand and upperBound must be powers of 2. -func applyUpperBound(rand uint64, bitsInRand int, upperBound *uint64) uint64 { - if upperBound == nil { - return rand - } else if *upperBound == 0 { - panic("sliceRandom called with upperBound of 0") - } - // Len64() returns the amount of bits needed to represent upperBound. Subtract 1 to get the - // amount of bits requested by the given upperBound as we want to return a value in the [0, upperBound) range. - // Note that upperBound is assumed to be a power of 2. - // - // For example, if upperBound = 128, then bits = 8 - 1 = 7 random bits to be returned. - // To get that amount of random bits from rand, subtract bits from bitsInRand, i.e. - // shift = 32 - 7 = 25. Shifting rand 25 positions would leave 7 of its random bits. - bits := bits.Len64(*upperBound) - 1 - shift := bitsInRand - bits - // If the shift ends up negative or 0, just return rand without any shifts. - if shift <= 0 { - return rand - } - return rand >> shift -} - -func generateRandom(environment EVMEnvironment, caller common.Address, resultType FheUintType, upperBound *uint64) ([]byte, error) { - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() { - return importRandomCiphertext(environment, resultType), nil - } - - // Get the RNG nonce. - protectedStorage := fhevm_crypto.CreateProtectedStorageContractAddress(caller) - currentRngNonceBytes := environment.GetState(protectedStorage, rngNonceKey).Bytes() - - // Increment the RNG nonce by 1. - nextRngNonce := newInt(currentRngNonceBytes) - nextRngNonce = nextRngNonce.AddUint64(nextRngNonce, 1) - environment.SetState(protectedStorage, rngNonceKey, nextRngNonce.Bytes32()) - - // Compute the seed and use it to create a new cipher. - hasher := crypto.NewKeccakState() - hasher.Write(globalRngSeed) - hasher.Write(caller.Bytes()) - seed := common.Hash{} - _, err := hasher.Read(seed[:]) - if err != nil { - return nil, err - } - // The RNG nonce bytes are of size chacha20.NonceSizeX, which is assumed to be 24 bytes (see init() above). - // Since uint256.Int.z[0] is the least significant byte and since uint256.Int.Bytes32() serializes - // in order of z[3], z[2], z[1], z[0], we want to essentially ignore the first byte, i.e. z[3], because - // it will always be 0 as the nonce size is 24. - cipher, err := chacha20.NewUnauthenticatedCipher(seed.Bytes(), currentRngNonceBytes[32-chacha20.NonceSizeX:32]) - if err != nil { - return nil, err - } - - // XOR a byte array of 0s with the stream from the cipher and receive the result in the same array. - // Apply upperBound, if set. - var randUint uint64 - switch resultType { - case FheUint8: - randBytes := make([]byte, 1) - cipher.XORKeyStream(randBytes, randBytes) - randUint = uint64(randBytes[0]) - randUint = uint64(applyUpperBound(randUint, 8, upperBound)) - case FheUint16: - randBytes := make([]byte, 2) - cipher.XORKeyStream(randBytes, randBytes) - randUint = uint64(binary.BigEndian.Uint16(randBytes)) - randUint = uint64(applyUpperBound(randUint, 16, upperBound)) - case FheUint32: - randBytes := make([]byte, 4) - cipher.XORKeyStream(randBytes, randBytes) - randUint = uint64(binary.BigEndian.Uint32(randBytes)) - randUint = uint64(applyUpperBound(randUint, 32, upperBound)) - case FheUint64: - randBytes := make([]byte, 8) - cipher.XORKeyStream(randBytes, randBytes) - randUint = uint64(binary.BigEndian.Uint64(randBytes)) - randUint = uint64(applyUpperBound(randUint, 64, upperBound)) - default: - return nil, fmt.Errorf("generateRandom() invalid type requested: %d", resultType) - } - - // Trivially encrypt the random integer. - randCt := new(tfheCiphertext) - randBigInt := big.NewInt(0) - randBigInt.SetUint64(randUint) - randCt.trivialEncrypt(*randBigInt, resultType) - importCiphertext(environment, randCt) - - if err != nil { - return nil, err - } - ctHash := randCt.getHash() - return ctHash[:], nil -} - -func fheRandRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - if environment.IsEthCall() { - msg := "fheRand cannot be called via EthCall, because it needs to mutate internal state" - logger.Error(msg) - return nil, errors.New(msg) - } - if len(input) != 1 || !isValidType(input[0]) { - msg := "fheRand input len must be at least 1 byte and be a valid FheUint type" - logger.Error(msg, "input", hex.EncodeToString(input), "len", len(input)) - return nil, errors.New(msg) - } - resultType := FheUintType(input[0]) - var noUpperBound *uint64 = nil - return generateRandom(environment, caller, resultType, noUpperBound) -} - -func fheRandBoundedRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - if environment.IsEthCall() { - msg := "fheRandBoundedRun cannot be called via EthCall, because it needs to mutate internal state" - logger.Error(msg) - return nil, errors.New(msg) - } - randType, bound, err := parseRandUpperBoundInput(input) - if err != nil { - msg := "fheRandBounded bound error" - logger.Error(msg, "input", hex.EncodeToString(input), "err", err) - return nil, errors.New(msg) - } - bound64 := bound.Uint64() - return generateRandom(environment, caller, randType, &bound64) -} - -func fheIfThenElseRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - first, second, third, err := get3VerifiedOperands(environment, input) - if err != nil { - logger.Error("fheIfThenElse inputs not verified", "err", err, "input", hex.EncodeToString(input)) - return nil, err - } - - if second.ciphertext.fheUintType != third.ciphertext.fheUintType { - msg := "fheIfThenElse operand type mismatch" - logger.Error(msg, "second", second.ciphertext.fheUintType, "third", third.ciphertext.fheUintType) - return nil, errors.New(msg) - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, second.ciphertext.fheUintType), nil - } - - result, err := first.ciphertext.ifThenElse(second.ciphertext, third.ciphertext) - if err != nil { - logger.Error("fheIfThenElse failed", "err", err) - return nil, err - } - importCiphertext(environment, result) - - resultHash := result.getHash() - logger.Info("fheIfThenElse success", "first", first.ciphertext.getHash().Hex(), "second", second.ciphertext.getHash().Hex(), "third", third.ciphertext.getHash().Hex(), "result", resultHash.Hex()) - return resultHash[:], nil -} - -func verifyCiphertextRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - if len(input) <= 1 { - msg := "verifyCiphertext Run() input needs to contain a ciphertext and one byte for its type" - logger.Error(msg, "len", len(input)) - return nil, errors.New(msg) - } - - ctBytes := input[:len(input)-1] - ctTypeByte := input[len(input)-1] - if !isValidType(ctTypeByte) { - msg := "verifyCiphertext Run() ciphertext type is invalid" - logger.Error(msg, "type", ctTypeByte) - return nil, errors.New(msg) - } - ctType := FheUintType(ctTypeByte) - - expectedSize, found := compactFheCiphertextSize[ctType] - if !found || expectedSize != uint(len(ctBytes)) { - msg := "verifyCiphertext Run() compact ciphertext size is invalid" - logger.Error(msg, "type", ctTypeByte, "size", len(ctBytes), "expectedSize", expectedSize) - return nil, errors.New(msg) - } - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, ctType), nil - } - - ct := new(tfheCiphertext) - err := ct.deserializeCompact(ctBytes, ctType) - if err != nil { - logger.Error("verifyCiphertext failed to deserialize input ciphertext", - "err", err, - "len", len(ctBytes), - "ctBytes64", hex.EncodeToString(ctBytes[:minInt(len(ctBytes), 64)])) - return nil, err - } - ctHash := ct.getHash() - importCiphertext(environment, ct) - if environment.IsCommitting() { - logger.Info("verifyCiphertext success", - "ctHash", ctHash.Hex(), - "ctBytes64", hex.EncodeToString(ctBytes[:minInt(len(ctBytes), 64)])) - } - return ctHash.Bytes(), nil -} - -func classicalPublicKeyEncrypt(value *big.Int, userPublicKey []byte) ([]byte, error) { - encrypted, err := box.SealAnonymous(nil, value.Bytes(), (*[32]byte)(userPublicKey), rand.Reader) - if err != nil { - return nil, err - } - return encrypted, nil -} - -func encryptToUserKey(value *big.Int, pubKey []byte) ([]byte, error) { - ct, err := classicalPublicKeyEncrypt(value, pubKey) - if err != nil { - return nil, err - } - - return ct, nil -} - -func reencryptRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - if !environment.IsEthCall() { - msg := "reencrypt only supported on EthCall" - logger.Error(msg) - return nil, errors.New(msg) - } - if len(input) != 64 { - msg := "reencrypt input len must be 64 bytes" - logger.Error(msg, "input", hex.EncodeToString(input), "len", len(input)) - return nil, errors.New(msg) - } - ct := getVerifiedCiphertext(environment, common.BytesToHash(input[0:32])) - if ct != nil { - // Make sure we don't decrypt before any optimistic requires are checked. - // optReqResult, optReqErr := evaluateRemainingOptimisticRequires(environment) - // if optReqErr != nil { - // return nil, optReqErr - // } else if !optReqResult { - // return nil, ErrExecutionReverted - // } - - var fheType kms.FheType - switch ct.ciphertext.fheUintType { - case FheUint8: - fheType = kms.FheType_Euint8 - case FheUint16: - fheType = kms.FheType_Euint16 - case FheUint32: - fheType = kms.FheType_Euint32 - case FheUint64: - fheType = kms.FheType_Euint64 - } - - pubKey := input[32:64] - - // TODO: generate merkle proof for some data - proof := &kms.Proof{ - Height: 3, - MerklePatriciaProof: []byte{}, - } - - reencryptionRequest := &kms.ReencryptionRequest{ - FheType: fheType, - Ciphertext: ct.ciphertext.serialization, - Request: pubKey, // TODO: change according to the structure of `Request` - Proof: proof, - } - - conn, err := grpc.Dial(kms.KmsEndpointAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) - if err != nil { - return nil, errors.New("kms unreachable") - } - defer conn.Close() - - ep := kms.NewKmsEndpointClient(conn) - - ctx, cancel := context.WithTimeout(context.Background(), time.Second) - defer cancel() - - res, err := ep.Reencrypt(ctx, reencryptionRequest) - if err != nil { - return nil, err - } - - // TODO: decide if `res.Signature` should be verified here - - var reencryptedValue = res.ReencryptedCiphertext - - logger.Info("reencrypt success", "input", hex.EncodeToString(input), "callerAddr", caller, "reencryptedValue", reencryptedValue, "len", len(reencryptedValue)) - return toEVMBytes(reencryptedValue), nil - } - msg := "reencrypt unverified ciphertext handle" - logger.Error(msg, "input", hex.EncodeToString(input)) - return nil, errors.New(msg) -} - -func optimisticRequireRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - if len(input) != 32 { - msg := "optimisticRequire input len must be 32 bytes" - logger.Error(msg, "input", hex.EncodeToString(input), "len", len(input)) - return nil, errors.New(msg) - } - ct := getVerifiedCiphertext(environment, common.BytesToHash(input)) - if ct == nil { - msg := "optimisticRequire unverified handle" - logger.Error(msg, "input", hex.EncodeToString(input)) - return nil, errors.New(msg) - } - // If we are doing gas estimation, don't do anything as we would assume all requires are true. - if !environment.IsCommitting() && !environment.IsEthCall() { - return nil, nil - } - if ct.ciphertext.fheUintType != FheUint8 { - msg := "optimisticRequire ciphertext type is not FheUint8" - logger.Error(msg, "type", ct.ciphertext.fheUintType) - return nil, errors.New(msg) - } - environment.FhevmData().optimisticRequires = append(environment.FhevmData().optimisticRequires, ct.ciphertext) - return nil, nil -} - -func decryptRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - // if not gas estimation and not view function fail if decryptions are disabled in transactions - if environment.IsCommitting() && !environment.IsEthCall() && environment.FhevmParams().DisableDecryptionsInTransaction { - msg := "decryptions during transaction are disabled" - logger.Error(msg, "input", hex.EncodeToString(input)) - return nil, errors.New(msg) - } - if len(input) != 32 { - msg := "decrypt input len must be 32 bytes" - logger.Error(msg, "input", hex.EncodeToString(input), "len", len(input)) - return nil, errors.New(msg) - } - ct := getVerifiedCiphertext(environment, common.BytesToHash(input)) - if ct == nil { - msg := "decrypt unverified handle" - logger.Error(msg, "input", hex.EncodeToString(input)) - return nil, errors.New(msg) - } - - // If we are doing gas estimation, skip decryption and make sure we return the maximum possible value. - // We need that, because non-zero bytes cost more than zero bytes in some contexts (e.g. SSTORE or memory operations). - if !environment.IsCommitting() && !environment.IsEthCall() { - return bytes.Repeat([]byte{0xFF}, 32), nil - } - // Make sure we don't decrypt before any optimistic requires are checked. - optReqResult, optReqErr := evaluateRemainingOptimisticRequires(environment) - if optReqErr != nil { - return nil, optReqErr - } else if !optReqResult { - return nil, ErrExecutionReverted - } - - plaintext, err := decryptValue(environment, ct.ciphertext) - if err != nil { - logger.Error("decrypt failed", "err", err) - return nil, err - } - - logger.Info("decrypt success", "plaintext", plaintext) - - // Always return a 32-byte big-endian integer. - ret := make([]byte, 32) - bigIntValue := big.NewInt(0) - bigIntValue.SetUint64(plaintext) - bigIntValue.FillBytes(ret) - return ret, nil -} - -func decryptValue(environment EVMEnvironment, ct *tfheCiphertext) (uint64, error) { - - logger := environment.GetLogger() - var fheType kms.FheType - switch ct.fheUintType { - case FheUint8: - fheType = kms.FheType_Euint8 - case FheUint16: - fheType = kms.FheType_Euint16 - case FheUint32: - fheType = kms.FheType_Euint32 - case FheUint64: - fheType = kms.FheType_Euint64 - } - - // TODO: generate merkle proof for some data - proof := &kms.Proof{ - Height: 4, - MerklePatriciaProof: []byte{}, - } - - decryptionRequest := &kms.DecryptionRequest{ - FheType: fheType, - Ciphertext: ct.serialization, - Request: []byte{}, // TODO: change according to the structure of `Request` - Proof: proof, - } - - conn, err := grpc.Dial(kms.KmsEndpointAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) - if err != nil { - return 0, errors.New("kms unreachable") - } - defer conn.Close() - - ep := kms.NewKmsEndpointClient(conn) - - ctx, cancel := context.WithTimeout(context.Background(), time.Second) - defer cancel() - - res, err := ep.Decrypt(ctx, decryptionRequest) - if err != nil { - logger.Error("decrypt failed", "err", err) - return 0, err - } - - return uint64(res.Plaintext), err -} - -// If there are optimistic requires, check them by doing bitwise AND on all of them. -// That works, because we assume their values are either 0 or 1. If there is at least -// one 0, the result will be 0 (false). -func evaluateRemainingOptimisticRequires(environment EVMEnvironment) (bool, error) { - requires := environment.FhevmData().optimisticRequires - len := len(requires) - defer func() { environment.FhevmData().optimisticRequires = make([]*tfheCiphertext, 0) }() - if len != 0 { - var cumulative *tfheCiphertext = requires[0] - var err error - for i := 1; i < len; i++ { - cumulative, err = cumulative.bitand(requires[i]) - if err != nil { - environment.GetLogger().Error("evaluateRemainingOptimisticRequires bitand failed", "err", err) - return false, err - } - } - result, err := decryptValue(environment, cumulative) - return result != 0, err - } - return true, nil -} - -func castRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - if len(input) != 33 { - msg := "cast Run() input needs to contain a ciphertext and one byte for its type" - logger.Error(msg, "len", len(input)) - return nil, errors.New(msg) - } - - ct := getVerifiedCiphertext(environment, common.BytesToHash(input[0:32])) - if ct == nil { - logger.Error("cast input not verified") - return nil, errors.New("unverified ciphertext handle") - } - - if !isValidType(input[32]) { - logger.Error("invalid type to cast to") - return nil, errors.New("invalid type provided") - } - castToType := FheUintType(input[32]) - - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return importRandomCiphertext(environment, castToType), nil - } - - res, err := ct.ciphertext.castTo(castToType) - if err != nil { - msg := "cast Run() error casting ciphertext to" - logger.Error(msg, "type", castToType) - return nil, errors.New(msg) - } - - resHash := res.getHash() - - importCiphertext(environment, res) - if environment.IsCommitting() { - logger.Info("cast success", - "ctHash", resHash.Hex(), - ) - } - - return resHash.Bytes(), nil -} - -var fhePubKeyHashPrecompile = common.BytesToAddress([]byte{93}) -var fhePubKeyHashSlot = common.Hash{} - -func fhePubKeyRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - existing := environment.GetState(fhePubKeyHashPrecompile, fhePubKeyHashSlot) - if existing != pksHash { - msg := "fhePubKey FHE public key hash doesn't match one stored in state" - environment.GetLogger().Error(msg, "existing", existing.Hex(), "pksHash", pksHash.Hex()) - return nil, errors.New(msg) - } - // serialize public key - pksBytes, err := serializePublicKey(pks) - if err != nil { - return nil, err - } - // If we have a single byte with the value of 1, return as an EVM array. Otherwise, returh the raw bytes. - if len(input) == 1 && input[0] == 1 { - return toEVMBytes(pksBytes), nil - } else { - return pksBytes, nil - } -} - -func trivialEncryptRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool) ([]byte, error) { - logger := environment.GetLogger() - if len(input) != 33 { - msg := "trivialEncrypt input len must be 33 bytes" - logger.Error(msg, "input", hex.EncodeToString(input), "len", len(input)) - return nil, errors.New(msg) - } - - valueToEncrypt := *new(big.Int).SetBytes(input[0:32]) - encryptToType := FheUintType(input[32]) - - ct := new(tfheCiphertext).trivialEncrypt(valueToEncrypt, encryptToType) - - ctHash := ct.getHash() - importCiphertext(environment, ct) - if environment.IsCommitting() { - logger.Info("trivialEncrypt success", - "ctHash", ctHash.Hex(), - "valueToEncrypt", valueToEncrypt.Uint64()) - } - return ctHash.Bytes(), nil + return } diff --git a/fhevm/tfhe_ciphertext.go b/fhevm/tfhe_ciphertext.go index 5c8b485..cff640a 100644 --- a/fhevm/tfhe_ciphertext.go +++ b/fhevm/tfhe_ciphertext.go @@ -23,15 +23,26 @@ const ( FheUint64 FheUintType = 3 ) +func isValidFheType(t byte) bool { + if uint8(t) < uint8(FheUint8) || uint8(t) > uint8(FheUint64) { + return false + } + return true +} + // Represents an expanded TFHE ciphertext. -type tfheCiphertext struct { +type TfheCiphertext struct { serialization []byte hash *common.Hash fheUintType FheUintType } +func (ct *TfheCiphertext) Type() FheUintType { + return ct.fheUintType +} + // Deserializes a TFHE ciphertext. -func (ct *tfheCiphertext) deserialize(in []byte, t FheUintType) error { +func (ct *TfheCiphertext) Deserialize(in []byte, t FheUintType) error { switch t { case FheUint8: ptr := C.deserialize_fhe_uint8(toDynamicBufferView((in))) @@ -69,7 +80,7 @@ func (ct *tfheCiphertext) deserialize(in []byte, t FheUintType) error { // Deserializes a compact TFHE ciphetext. // Note: After the compact TFHE ciphertext has been serialized, subsequent calls to serialize() // will produce non-compact ciphertext serialziations. -func (ct *tfheCiphertext) deserializeCompact(in []byte, t FheUintType) error { +func (ct *TfheCiphertext) DeserializeCompact(in []byte, t FheUintType) error { switch t { case FheUint8: ptr := C.deserialize_compact_fhe_uint8(toDynamicBufferView((in))) @@ -125,7 +136,7 @@ func (ct *tfheCiphertext) deserializeCompact(in []byte, t FheUintType) error { // Encrypts a value as a TFHE ciphertext, using the compact public FHE key. // The resulting ciphertext is automaticaly expanded. -func (ct *tfheCiphertext) encrypt(value big.Int, t FheUintType) *tfheCiphertext { +func (ct *TfheCiphertext) Encrypt(value big.Int, t FheUintType) *TfheCiphertext { var ptr unsafe.Pointer var err error switch t { @@ -165,7 +176,7 @@ func (ct *tfheCiphertext) encrypt(value big.Int, t FheUintType) *tfheCiphertext return ct } -func (ct *tfheCiphertext) trivialEncrypt(value big.Int, t FheUintType) *tfheCiphertext { +func (ct *TfheCiphertext) TrivialEncrypt(value big.Int, t FheUintType) *TfheCiphertext { var ptr unsafe.Pointer var err error switch t { @@ -205,17 +216,17 @@ func (ct *tfheCiphertext) trivialEncrypt(value big.Int, t FheUintType) *tfheCiph return ct } -func (ct *tfheCiphertext) serialize() []byte { +func (ct *TfheCiphertext) Serialize() []byte { return ct.serialization } -func (ct *tfheCiphertext) executeUnaryCiphertextOperation(rhs *tfheCiphertext, +func (ct *TfheCiphertext) executeUnaryCiphertextOperation(rhs *TfheCiphertext, op8 func(ct unsafe.Pointer) unsafe.Pointer, op16 func(ct unsafe.Pointer) unsafe.Pointer, op32 func(ct unsafe.Pointer) unsafe.Pointer, - op64 func(ct unsafe.Pointer) unsafe.Pointer) (*tfheCiphertext, error) { + op64 func(ct unsafe.Pointer) unsafe.Pointer) (*TfheCiphertext, error) { - res := new(tfheCiphertext) + res := new(TfheCiphertext) res.fheUintType = ct.fheUintType res_ser := &C.DynamicBuffer{} switch ct.fheUintType { @@ -294,16 +305,16 @@ func (ct *tfheCiphertext) executeUnaryCiphertextOperation(rhs *tfheCiphertext, return res, nil } -func (lhs *tfheCiphertext) executeBinaryCiphertextOperation(rhs *tfheCiphertext, +func (lhs *TfheCiphertext) executeBinaryCiphertextOperation(rhs *TfheCiphertext, op8 func(lhs unsafe.Pointer, rhs unsafe.Pointer) unsafe.Pointer, op16 func(lhs unsafe.Pointer, rhs unsafe.Pointer) unsafe.Pointer, op32 func(lhs unsafe.Pointer, rhs unsafe.Pointer) unsafe.Pointer, - op64 func(lhs unsafe.Pointer, rhs unsafe.Pointer) unsafe.Pointer) (*tfheCiphertext, error) { + op64 func(lhs unsafe.Pointer, rhs unsafe.Pointer) unsafe.Pointer) (*TfheCiphertext, error) { if lhs.fheUintType != rhs.fheUintType { return nil, errors.New("binary operations are only well-defined for identical types") } - res := new(tfheCiphertext) + res := new(TfheCiphertext) res.fheUintType = lhs.fheUintType res_ser := &C.DynamicBuffer{} switch lhs.fheUintType { @@ -406,16 +417,16 @@ func (lhs *tfheCiphertext) executeBinaryCiphertextOperation(rhs *tfheCiphertext, return res, nil } -func (first *tfheCiphertext) executeTernaryCiphertextOperation(lhs *tfheCiphertext, rhs *tfheCiphertext, +func (first *TfheCiphertext) executeTernaryCiphertextOperation(lhs *TfheCiphertext, rhs *TfheCiphertext, op8 func(first unsafe.Pointer, lhs unsafe.Pointer, rhs unsafe.Pointer) unsafe.Pointer, op16 func(first unsafe.Pointer, lhs unsafe.Pointer, rhs unsafe.Pointer) unsafe.Pointer, op32 func(first unsafe.Pointer, lhs unsafe.Pointer, rhs unsafe.Pointer) unsafe.Pointer, - op64 func(first unsafe.Pointer, lhs unsafe.Pointer, rhs unsafe.Pointer) unsafe.Pointer) (*tfheCiphertext, error) { + op64 func(first unsafe.Pointer, lhs unsafe.Pointer, rhs unsafe.Pointer) unsafe.Pointer) (*TfheCiphertext, error) { if lhs.fheUintType != rhs.fheUintType { return nil, errors.New("ternary operations are only well-defined for identical types") } - res := new(tfheCiphertext) + res := new(TfheCiphertext) res.fheUintType = lhs.fheUintType res_ser := &C.DynamicBuffer{} switch lhs.fheUintType { @@ -542,12 +553,12 @@ func (first *tfheCiphertext) executeTernaryCiphertextOperation(lhs *tfheCipherte return res, nil } -func (lhs *tfheCiphertext) executeBinaryScalarOperation(rhs uint64, +func (lhs *TfheCiphertext) executeBinaryScalarOperation(rhs uint64, op8 func(lhs unsafe.Pointer, rhs C.uint8_t) unsafe.Pointer, op16 func(lhs unsafe.Pointer, rhs C.uint16_t) unsafe.Pointer, op32 func(lhs unsafe.Pointer, rhs C.uint32_t) unsafe.Pointer, - op64 func(lhs unsafe.Pointer, rhs C.uint64_t) unsafe.Pointer) (*tfheCiphertext, error) { - res := new(tfheCiphertext) + op64 func(lhs unsafe.Pointer, rhs C.uint64_t) unsafe.Pointer) (*TfheCiphertext, error) { + res := new(TfheCiphertext) res.fheUintType = lhs.fheUintType res_ser := &C.DynamicBuffer{} switch lhs.fheUintType { @@ -630,7 +641,7 @@ func (lhs *tfheCiphertext) executeBinaryScalarOperation(rhs uint64, return res, nil } -func (lhs *tfheCiphertext) add(rhs *tfheCiphertext) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) Add(rhs *TfheCiphertext) (*TfheCiphertext, error) { return lhs.executeBinaryCiphertextOperation(rhs, func(lhs unsafe.Pointer, rhs unsafe.Pointer) unsafe.Pointer { return C.add_fhe_uint8(lhs, rhs, sks) @@ -646,7 +657,7 @@ func (lhs *tfheCiphertext) add(rhs *tfheCiphertext) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) scalarAdd(rhs uint64) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) ScalarAdd(rhs uint64) (*TfheCiphertext, error) { return lhs.executeBinaryScalarOperation(rhs, func(lhs unsafe.Pointer, rhs C.uint8_t) unsafe.Pointer { return C.scalar_add_fhe_uint8(lhs, rhs, sks) @@ -662,7 +673,7 @@ func (lhs *tfheCiphertext) scalarAdd(rhs uint64) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) sub(rhs *tfheCiphertext) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) Sub(rhs *TfheCiphertext) (*TfheCiphertext, error) { return lhs.executeBinaryCiphertextOperation(rhs, func(lhs unsafe.Pointer, rhs unsafe.Pointer) unsafe.Pointer { return C.sub_fhe_uint8(lhs, rhs, sks) @@ -678,7 +689,7 @@ func (lhs *tfheCiphertext) sub(rhs *tfheCiphertext) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) scalarSub(rhs uint64) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) ScalarSub(rhs uint64) (*TfheCiphertext, error) { return lhs.executeBinaryScalarOperation(rhs, func(lhs unsafe.Pointer, rhs C.uint8_t) unsafe.Pointer { return C.scalar_sub_fhe_uint8(lhs, rhs, sks) @@ -694,7 +705,7 @@ func (lhs *tfheCiphertext) scalarSub(rhs uint64) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) mul(rhs *tfheCiphertext) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) Mul(rhs *TfheCiphertext) (*TfheCiphertext, error) { return lhs.executeBinaryCiphertextOperation(rhs, func(lhs unsafe.Pointer, rhs unsafe.Pointer) unsafe.Pointer { return C.mul_fhe_uint8(lhs, rhs, sks) @@ -710,7 +721,7 @@ func (lhs *tfheCiphertext) mul(rhs *tfheCiphertext) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) scalarMul(rhs uint64) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) ScalarMul(rhs uint64) (*TfheCiphertext, error) { return lhs.executeBinaryScalarOperation(rhs, func(lhs unsafe.Pointer, rhs C.uint8_t) unsafe.Pointer { return C.scalar_mul_fhe_uint8(lhs, rhs, sks) @@ -726,7 +737,7 @@ func (lhs *tfheCiphertext) scalarMul(rhs uint64) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) scalarDiv(rhs uint64) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) ScalarDiv(rhs uint64) (*TfheCiphertext, error) { return lhs.executeBinaryScalarOperation(rhs, func(lhs unsafe.Pointer, rhs C.uint8_t) unsafe.Pointer { return C.scalar_div_fhe_uint8(lhs, rhs, sks) @@ -742,7 +753,7 @@ func (lhs *tfheCiphertext) scalarDiv(rhs uint64) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) scalarRem(rhs uint64) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) ScalarRem(rhs uint64) (*TfheCiphertext, error) { return lhs.executeBinaryScalarOperation(rhs, func(lhs unsafe.Pointer, rhs C.uint8_t) unsafe.Pointer { return C.scalar_rem_fhe_uint8(lhs, rhs, sks) @@ -758,7 +769,7 @@ func (lhs *tfheCiphertext) scalarRem(rhs uint64) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) bitand(rhs *tfheCiphertext) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) Bitand(rhs *TfheCiphertext) (*TfheCiphertext, error) { return lhs.executeBinaryCiphertextOperation(rhs, func(lhs unsafe.Pointer, rhs unsafe.Pointer) unsafe.Pointer { return C.bitand_fhe_uint8(lhs, rhs, sks) @@ -774,7 +785,7 @@ func (lhs *tfheCiphertext) bitand(rhs *tfheCiphertext) (*tfheCiphertext, error) }) } -func (lhs *tfheCiphertext) bitor(rhs *tfheCiphertext) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) Bitor(rhs *TfheCiphertext) (*TfheCiphertext, error) { return lhs.executeBinaryCiphertextOperation(rhs, func(lhs unsafe.Pointer, rhs unsafe.Pointer) unsafe.Pointer { return C.bitor_fhe_uint8(lhs, rhs, sks) @@ -790,7 +801,7 @@ func (lhs *tfheCiphertext) bitor(rhs *tfheCiphertext) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) bitxor(rhs *tfheCiphertext) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) Bitxor(rhs *TfheCiphertext) (*TfheCiphertext, error) { return lhs.executeBinaryCiphertextOperation(rhs, func(lhs unsafe.Pointer, rhs unsafe.Pointer) unsafe.Pointer { return C.bitxor_fhe_uint8(lhs, rhs, sks) @@ -806,7 +817,7 @@ func (lhs *tfheCiphertext) bitxor(rhs *tfheCiphertext) (*tfheCiphertext, error) }) } -func (lhs *tfheCiphertext) shl(rhs *tfheCiphertext) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) Shl(rhs *TfheCiphertext) (*TfheCiphertext, error) { return lhs.executeBinaryCiphertextOperation(rhs, func(lhs unsafe.Pointer, rhs unsafe.Pointer) unsafe.Pointer { return C.shl_fhe_uint8(lhs, rhs, sks) @@ -822,7 +833,7 @@ func (lhs *tfheCiphertext) shl(rhs *tfheCiphertext) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) scalarShl(rhs uint64) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) ScalarShl(rhs uint64) (*TfheCiphertext, error) { return lhs.executeBinaryScalarOperation(rhs, func(lhs unsafe.Pointer, rhs C.uint8_t) unsafe.Pointer { return C.scalar_shl_fhe_uint8(lhs, rhs, sks) @@ -838,7 +849,7 @@ func (lhs *tfheCiphertext) scalarShl(rhs uint64) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) shr(rhs *tfheCiphertext) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) Shr(rhs *TfheCiphertext) (*TfheCiphertext, error) { return lhs.executeBinaryCiphertextOperation(rhs, func(lhs unsafe.Pointer, rhs unsafe.Pointer) unsafe.Pointer { return C.shr_fhe_uint8(lhs, rhs, sks) @@ -854,7 +865,7 @@ func (lhs *tfheCiphertext) shr(rhs *tfheCiphertext) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) scalarShr(rhs uint64) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) ScalarShr(rhs uint64) (*TfheCiphertext, error) { return lhs.executeBinaryScalarOperation(rhs, func(lhs unsafe.Pointer, rhs C.uint8_t) unsafe.Pointer { return C.scalar_shr_fhe_uint8(lhs, rhs, sks) @@ -870,7 +881,7 @@ func (lhs *tfheCiphertext) scalarShr(rhs uint64) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) eq(rhs *tfheCiphertext) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) Eq(rhs *TfheCiphertext) (*TfheCiphertext, error) { return lhs.executeBinaryCiphertextOperation(rhs, func(lhs unsafe.Pointer, rhs unsafe.Pointer) unsafe.Pointer { return C.eq_fhe_uint8(lhs, rhs, sks) @@ -886,7 +897,7 @@ func (lhs *tfheCiphertext) eq(rhs *tfheCiphertext) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) scalarEq(rhs uint64) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) ScalarEq(rhs uint64) (*TfheCiphertext, error) { return lhs.executeBinaryScalarOperation(rhs, func(lhs unsafe.Pointer, rhs C.uint8_t) unsafe.Pointer { return C.scalar_eq_fhe_uint8(lhs, rhs, sks) @@ -902,7 +913,7 @@ func (lhs *tfheCiphertext) scalarEq(rhs uint64) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) ne(rhs *tfheCiphertext) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) Ne(rhs *TfheCiphertext) (*TfheCiphertext, error) { return lhs.executeBinaryCiphertextOperation(rhs, func(lhs unsafe.Pointer, rhs unsafe.Pointer) unsafe.Pointer { return C.ne_fhe_uint8(lhs, rhs, sks) @@ -918,7 +929,7 @@ func (lhs *tfheCiphertext) ne(rhs *tfheCiphertext) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) scalarNe(rhs uint64) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) ScalarNe(rhs uint64) (*TfheCiphertext, error) { return lhs.executeBinaryScalarOperation(rhs, func(lhs unsafe.Pointer, rhs C.uint8_t) unsafe.Pointer { return C.scalar_ne_fhe_uint8(lhs, rhs, sks) @@ -934,7 +945,7 @@ func (lhs *tfheCiphertext) scalarNe(rhs uint64) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) ge(rhs *tfheCiphertext) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) Ge(rhs *TfheCiphertext) (*TfheCiphertext, error) { return lhs.executeBinaryCiphertextOperation(rhs, func(lhs unsafe.Pointer, rhs unsafe.Pointer) unsafe.Pointer { return C.ge_fhe_uint8(lhs, rhs, sks) @@ -950,7 +961,7 @@ func (lhs *tfheCiphertext) ge(rhs *tfheCiphertext) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) scalarGe(rhs uint64) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) ScalarGe(rhs uint64) (*TfheCiphertext, error) { return lhs.executeBinaryScalarOperation(rhs, func(lhs unsafe.Pointer, rhs C.uint8_t) unsafe.Pointer { return C.scalar_ge_fhe_uint8(lhs, rhs, sks) @@ -966,7 +977,7 @@ func (lhs *tfheCiphertext) scalarGe(rhs uint64) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) gt(rhs *tfheCiphertext) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) Gt(rhs *TfheCiphertext) (*TfheCiphertext, error) { return lhs.executeBinaryCiphertextOperation(rhs, func(lhs unsafe.Pointer, rhs unsafe.Pointer) unsafe.Pointer { return C.gt_fhe_uint8(lhs, rhs, sks) @@ -982,7 +993,7 @@ func (lhs *tfheCiphertext) gt(rhs *tfheCiphertext) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) scalarGt(rhs uint64) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) ScalarGt(rhs uint64) (*TfheCiphertext, error) { return lhs.executeBinaryScalarOperation(rhs, func(lhs unsafe.Pointer, rhs C.uint8_t) unsafe.Pointer { return C.scalar_gt_fhe_uint8(lhs, rhs, sks) @@ -998,7 +1009,7 @@ func (lhs *tfheCiphertext) scalarGt(rhs uint64) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) le(rhs *tfheCiphertext) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) Le(rhs *TfheCiphertext) (*TfheCiphertext, error) { return lhs.executeBinaryCiphertextOperation(rhs, func(lhs unsafe.Pointer, rhs unsafe.Pointer) unsafe.Pointer { return C.le_fhe_uint8(lhs, rhs, sks) @@ -1014,7 +1025,7 @@ func (lhs *tfheCiphertext) le(rhs *tfheCiphertext) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) scalarLe(rhs uint64) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) ScalarLe(rhs uint64) (*TfheCiphertext, error) { return lhs.executeBinaryScalarOperation(rhs, func(lhs unsafe.Pointer, rhs C.uint8_t) unsafe.Pointer { return C.scalar_le_fhe_uint8(lhs, rhs, sks) @@ -1031,7 +1042,7 @@ func (lhs *tfheCiphertext) scalarLe(rhs uint64) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) lt(rhs *tfheCiphertext) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) Lt(rhs *TfheCiphertext) (*TfheCiphertext, error) { return lhs.executeBinaryCiphertextOperation(rhs, func(lhs unsafe.Pointer, rhs unsafe.Pointer) unsafe.Pointer { return C.lt_fhe_uint8(lhs, rhs, sks) @@ -1047,7 +1058,7 @@ func (lhs *tfheCiphertext) lt(rhs *tfheCiphertext) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) scalarLt(rhs uint64) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) ScalarLt(rhs uint64) (*TfheCiphertext, error) { return lhs.executeBinaryScalarOperation(rhs, func(lhs unsafe.Pointer, rhs C.uint8_t) unsafe.Pointer { return C.scalar_lt_fhe_uint8(lhs, rhs, sks) @@ -1063,7 +1074,7 @@ func (lhs *tfheCiphertext) scalarLt(rhs uint64) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) min(rhs *tfheCiphertext) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) Min(rhs *TfheCiphertext) (*TfheCiphertext, error) { return lhs.executeBinaryCiphertextOperation(rhs, func(lhs unsafe.Pointer, rhs unsafe.Pointer) unsafe.Pointer { return C.min_fhe_uint8(lhs, rhs, sks) @@ -1079,7 +1090,7 @@ func (lhs *tfheCiphertext) min(rhs *tfheCiphertext) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) scalarMin(rhs uint64) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) ScalarMin(rhs uint64) (*TfheCiphertext, error) { return lhs.executeBinaryScalarOperation(rhs, func(lhs unsafe.Pointer, rhs C.uint8_t) unsafe.Pointer { return C.scalar_min_fhe_uint8(lhs, rhs, sks) @@ -1095,7 +1106,7 @@ func (lhs *tfheCiphertext) scalarMin(rhs uint64) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) max(rhs *tfheCiphertext) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) Max(rhs *TfheCiphertext) (*TfheCiphertext, error) { return lhs.executeBinaryCiphertextOperation(rhs, func(lhs unsafe.Pointer, rhs unsafe.Pointer) unsafe.Pointer { return C.max_fhe_uint8(lhs, rhs, sks) @@ -1111,7 +1122,7 @@ func (lhs *tfheCiphertext) max(rhs *tfheCiphertext) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) scalarMax(rhs uint64) (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) ScalarMax(rhs uint64) (*TfheCiphertext, error) { return lhs.executeBinaryScalarOperation(rhs, func(lhs unsafe.Pointer, rhs C.uint8_t) unsafe.Pointer { return C.scalar_max_fhe_uint8(lhs, rhs, sks) @@ -1127,7 +1138,7 @@ func (lhs *tfheCiphertext) scalarMax(rhs uint64) (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) neg() (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) Neg() (*TfheCiphertext, error) { return lhs.executeUnaryCiphertextOperation(lhs, func(lhs unsafe.Pointer) unsafe.Pointer { return C.neg_fhe_uint8(lhs, sks) @@ -1143,7 +1154,7 @@ func (lhs *tfheCiphertext) neg() (*tfheCiphertext, error) { }) } -func (lhs *tfheCiphertext) not() (*tfheCiphertext, error) { +func (lhs *TfheCiphertext) Not() (*TfheCiphertext, error) { return lhs.executeUnaryCiphertextOperation(lhs, func(lhs unsafe.Pointer) unsafe.Pointer { return C.not_fhe_uint8(lhs, sks) @@ -1159,7 +1170,7 @@ func (lhs *tfheCiphertext) not() (*tfheCiphertext, error) { }) } -func (condition *tfheCiphertext) ifThenElse(lhs *tfheCiphertext, rhs *tfheCiphertext) (*tfheCiphertext, error) { +func (condition *TfheCiphertext) IfThenElse(lhs *TfheCiphertext, rhs *TfheCiphertext) (*TfheCiphertext, error) { return condition.executeTernaryCiphertextOperation(lhs, rhs, func(condition unsafe.Pointer, lhs unsafe.Pointer, rhs unsafe.Pointer) unsafe.Pointer { return C.if_then_else_fhe_uint8(condition, lhs, rhs, sks) @@ -1175,12 +1186,12 @@ func (condition *tfheCiphertext) ifThenElse(lhs *tfheCiphertext, rhs *tfheCipher }) } -func (ct *tfheCiphertext) castTo(castToType FheUintType) (*tfheCiphertext, error) { +func (ct *TfheCiphertext) CastTo(castToType FheUintType) (*TfheCiphertext, error) { if ct.fheUintType == castToType { return nil, errors.New("casting to same type is not supported") } - res := new(tfheCiphertext) + res := new(TfheCiphertext) res.fheUintType = castToType switch ct.fheUintType { @@ -1401,7 +1412,7 @@ func (ct *tfheCiphertext) castTo(castToType FheUintType) (*tfheCiphertext, error return res, nil } -func (ct *tfheCiphertext) decrypt() (big.Int, error) { +func (ct *TfheCiphertext) Decrypt() (big.Int, error) { if cks == nil { return *new(big.Int).SetUint64(0), errors.New("cks is not initialized") } @@ -1453,12 +1464,12 @@ func (ct *tfheCiphertext) decrypt() (big.Int, error) { return *new(big.Int).SetUint64(value), nil } -func (ct *tfheCiphertext) computeHash() { +func (ct *TfheCiphertext) computeHash() { hash := common.BytesToHash(crypto.Keccak256(ct.serialization)) ct.hash = &hash } -func (ct *tfheCiphertext) getHash() common.Hash { +func (ct *TfheCiphertext) GetHash() common.Hash { if ct.hash != nil { return *ct.hash } diff --git a/fhevm/tfhe_key_management.go b/fhevm/tfhe_key_management.go index 4dc2c68..d4d4d3c 100644 --- a/fhevm/tfhe_key_management.go +++ b/fhevm/tfhe_key_management.go @@ -19,9 +19,19 @@ import ( // Expanded TFHE ciphertext sizes by type, in bytes. var expandedFheCiphertextSize map[FheUintType]uint +func GetExpandedFheCiphertextSize(t FheUintType) (size uint, found bool) { + size, found = expandedFheCiphertextSize[t] + return +} + // Compact TFHE ciphertext sizes by type, in bytes. var compactFheCiphertextSize map[FheUintType]uint +func GetCompactFheCiphertextSize(t FheUintType) (size uint, found bool) { + size, found = compactFheCiphertextSize[t] + return +} + // server key: evaluation key var sks unsafe.Pointer @@ -32,6 +42,11 @@ var cks unsafe.Pointer var pks unsafe.Pointer var pksHash common.Hash +// Get public key hash +func GetPksHash() common.Hash { + return pksHash +} + // Generate keys for the fhevm (sks, cks, psk) func generateFhevmKeys() (unsafe.Pointer, unsafe.Pointer, unsafe.Pointer) { var keys = C.generate_fhevm_keys() @@ -51,10 +66,10 @@ func initCiphertextSizes() { expandedFheCiphertextSize = make(map[FheUintType]uint) compactFheCiphertextSize = make(map[FheUintType]uint) - expandedFheCiphertextSize[FheUint8] = uint(len(new(tfheCiphertext).trivialEncrypt(*big.NewInt(0), FheUint8).serialize())) - expandedFheCiphertextSize[FheUint16] = uint(len(new(tfheCiphertext).trivialEncrypt(*big.NewInt(0), FheUint16).serialize())) - expandedFheCiphertextSize[FheUint32] = uint(len(new(tfheCiphertext).trivialEncrypt(*big.NewInt(0), FheUint32).serialize())) - expandedFheCiphertextSize[FheUint64] = uint(len(new(tfheCiphertext).trivialEncrypt(*big.NewInt(0), FheUint64).serialize())) + expandedFheCiphertextSize[FheUint8] = uint(len(new(TfheCiphertext).TrivialEncrypt(*big.NewInt(0), FheUint8).Serialize())) + expandedFheCiphertextSize[FheUint16] = uint(len(new(TfheCiphertext).TrivialEncrypt(*big.NewInt(0), FheUint16).Serialize())) + expandedFheCiphertextSize[FheUint32] = uint(len(new(TfheCiphertext).TrivialEncrypt(*big.NewInt(0), FheUint32).Serialize())) + expandedFheCiphertextSize[FheUint64] = uint(len(new(TfheCiphertext).TrivialEncrypt(*big.NewInt(0), FheUint64).Serialize())) compactFheCiphertextSize[FheUint8] = uint(len(encryptAndSerializeCompact(0, FheUint8))) compactFheCiphertextSize[FheUint16] = uint(len(encryptAndSerializeCompact(0, FheUint16))) diff --git a/fhevm/tfhe_test.go b/fhevm/tfhe_test.go index 8c6b715..6caa7b0 100644 --- a/fhevm/tfhe_test.go +++ b/fhevm/tfhe_test.go @@ -34,9 +34,9 @@ func TfheEncryptDecrypt(t *testing.T, fheUintType FheUintType) { case FheUint64: val.SetUint64(13333377777777777) } - ct := new(tfheCiphertext) - ct.encrypt(val, fheUintType) - res, err := ct.decrypt() + ct := new(TfheCiphertext) + ct.Encrypt(val, fheUintType) + res, err := ct.Decrypt() if err != nil || res.Uint64() != val.Uint64() { t.Fatalf("%d != %d", val.Uint64(), res.Uint64()) } @@ -54,9 +54,9 @@ func TfheTrivialEncryptDecrypt(t *testing.T, fheUintType FheUintType) { case FheUint64: val.SetUint64(13333377777777777) } - ct := new(tfheCiphertext) - ct.trivialEncrypt(val, fheUintType) - res, err := ct.decrypt() + ct := new(TfheCiphertext) + ct.TrivialEncrypt(val, fheUintType) + res, err := ct.Decrypt() if err != nil || res.Uint64() != val.Uint64() { t.Fatalf("%d != %d", val.Uint64(), res.Uint64()) } @@ -74,15 +74,15 @@ func TfheSerializeDeserialize(t *testing.T, fheUintType FheUintType) { case FheUint64: val = *big.NewInt(13333377777777777) } - ct1 := new(tfheCiphertext) - ct1.encrypt(val, fheUintType) - ct1Ser := ct1.serialize() - ct2 := new(tfheCiphertext) - err := ct2.deserialize(ct1Ser, fheUintType) + ct1 := new(TfheCiphertext) + ct1.Encrypt(val, fheUintType) + ct1Ser := ct1.Serialize() + ct2 := new(TfheCiphertext) + err := ct2.Deserialize(ct1Ser, fheUintType) if err != nil { t.Fatalf("deserialization failed") } - ct2Ser := ct2.serialize() + ct2Ser := ct2.Serialize() if !bytes.Equal(ct1Ser, ct2Ser) { t.Fatalf("serialization is non-deterministic") } @@ -102,25 +102,25 @@ func TfheSerializeDeserializeCompact(t *testing.T, fheUintType FheUintType) { } ser := encryptAndSerializeCompact(val, fheUintType) - ct1 := new(tfheCiphertext) - err := ct1.deserializeCompact(ser, fheUintType) + ct1 := new(TfheCiphertext) + err := ct1.DeserializeCompact(ser, fheUintType) if err != nil { t.Fatalf("ct1 compact deserialization failed") } - ct1Ser := ct1.serialize() + ct1Ser := ct1.Serialize() - ct2 := new(tfheCiphertext) - err = ct2.deserialize(ct1Ser, fheUintType) + ct2 := new(TfheCiphertext) + err = ct2.Deserialize(ct1Ser, fheUintType) if err != nil { t.Fatalf("ct2 deserialization failed") } - ct2Ser := ct2.serialize() + ct2Ser := ct2.Serialize() if !bytes.Equal(ct1Ser, ct2Ser) { t.Fatalf("serialization is non-deterministic") } - decrypted, err := ct2.decrypt() + decrypted, err := ct2.Decrypt() if err != nil || uint64(decrypted.Uint64()) != val { t.Fatalf("decrypted value is incorrect") } @@ -138,25 +138,25 @@ func TfheTrivialSerializeDeserialize(t *testing.T, fheUintType FheUintType) { case FheUint64: val = *big.NewInt(13333377777777777) } - ct1 := new(tfheCiphertext) - ct1.trivialEncrypt(val, fheUintType) - ct1Ser := ct1.serialize() - ct2 := new(tfheCiphertext) - err := ct2.deserialize(ct1Ser, fheUintType) + ct1 := new(TfheCiphertext) + ct1.TrivialEncrypt(val, fheUintType) + ct1Ser := ct1.Serialize() + ct2 := new(TfheCiphertext) + err := ct2.Deserialize(ct1Ser, fheUintType) if err != nil { t.Fatalf("deserialization failed") } - ct2Ser := ct2.serialize() + ct2Ser := ct2.Serialize() if !bytes.Equal(ct1Ser, ct2Ser) { t.Fatalf("trivial serialization is non-deterministic") } } func TfheDeserializeFailure(t *testing.T, fheUintType FheUintType) { - ct := new(tfheCiphertext) + ct := new(TfheCiphertext) input := make([]byte, 1) input[0] = 42 - err := ct.deserialize(input, fheUintType) + err := ct.Deserialize(input, fheUintType) if err == nil { t.Fatalf("deserialization must have failed") } @@ -175,20 +175,20 @@ func TfheDeserializeCompact(t *testing.T, fheUintType FheUintType) { val = 13333377777777777 } ser := encryptAndSerializeCompact(val, fheUintType) - ct := new(tfheCiphertext) - err := ct.deserializeCompact(ser, fheUintType) + ct := new(TfheCiphertext) + err := ct.DeserializeCompact(ser, fheUintType) if err != nil { t.Fatalf("compact deserialization failed") } - decryptedVal, err := ct.decrypt() + decryptedVal, err := ct.Decrypt() if err != nil || uint64(decryptedVal.Uint64()) != val { t.Fatalf("compact deserialization wrong decryption") } } func TfheDeserializeCompactFailure(t *testing.T, fheUintType FheUintType) { - ct := new(tfheCiphertext) - err := ct.deserializeCompact(make([]byte, 10), fheUintType) + ct := new(TfheCiphertext) + err := ct.DeserializeCompact(make([]byte, 10), fheUintType) if err == nil { t.Fatalf("compact deserialization must have failed") } @@ -211,12 +211,12 @@ func TfheAdd(t *testing.T, fheUintType FheUintType) { b.SetUint64(133337777777777) } expected := new(big.Int).Add(&a, &b) - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctB := new(tfheCiphertext) - ctB.encrypt(b, fheUintType) - ctRes, _ := ctA.add(ctB) - res, err := ctRes.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctB := new(TfheCiphertext) + ctB.Encrypt(b, fheUintType) + ctRes, _ := ctA.Add(ctB) + res, err := ctRes.Decrypt() if err != nil || res.Uint64() != expected.Uint64() { t.Fatalf("%d != %d", expected.Uint64(), res.Uint64()) } @@ -239,10 +239,10 @@ func TfheScalarAdd(t *testing.T, fheUintType FheUintType) { b.SetUint64(133337777777777) } expected := new(big.Int).Add(&a, &b) - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctRes, _ := ctA.scalarAdd(b.Uint64()) - res, err := ctRes.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctRes, _ := ctA.ScalarAdd(b.Uint64()) + res, err := ctRes.Decrypt() if err != nil || res.Uint64() != expected.Uint64() { t.Fatalf("%d != %d", expected.Uint64(), res.Uint64()) } @@ -265,12 +265,12 @@ func TfheSub(t *testing.T, fheUintType FheUintType) { b.SetUint64(133337777777777) } expected := new(big.Int).Sub(&a, &b) - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctB := new(tfheCiphertext) - ctB.encrypt(b, fheUintType) - ctRes, _ := ctA.sub(ctB) - res, err := ctRes.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctB := new(TfheCiphertext) + ctB.Encrypt(b, fheUintType) + ctRes, _ := ctA.Sub(ctB) + res, err := ctRes.Decrypt() if err != nil || res.Uint64() != expected.Uint64() { t.Fatalf("%d != %d", expected.Uint64(), res.Uint64()) } @@ -293,10 +293,10 @@ func TfheScalarSub(t *testing.T, fheUintType FheUintType) { b.SetUint64(133337777777777) } expected := new(big.Int).Sub(&a, &b) - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctRes, _ := ctA.scalarSub(b.Uint64()) - res, err := ctRes.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctRes, _ := ctA.ScalarSub(b.Uint64()) + res, err := ctRes.Decrypt() if err != nil || res.Uint64() != expected.Uint64() { t.Fatalf("%d != %d", expected.Uint64(), res.Uint64()) } @@ -319,12 +319,12 @@ func TfheMul(t *testing.T, fheUintType FheUintType) { b.SetUint64(133) } expected := new(big.Int).Mul(&a, &b) - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctB := new(tfheCiphertext) - ctB.encrypt(b, fheUintType) - ctRes, _ := ctA.mul(ctB) - res, err := ctRes.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctB := new(TfheCiphertext) + ctB.Encrypt(b, fheUintType) + ctRes, _ := ctA.Mul(ctB) + res, err := ctRes.Decrypt() if err != nil || res.Uint64() != expected.Uint64() { t.Fatalf("%d != %d", expected.Uint64(), res.Uint64()) } @@ -347,10 +347,10 @@ func TfheScalarMul(t *testing.T, fheUintType FheUintType) { b.SetUint64(133) } expected := new(big.Int).Mul(&a, &b) - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctRes, _ := ctA.scalarMul(b.Uint64()) - res, err := ctRes.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctRes, _ := ctA.ScalarMul(b.Uint64()) + res, err := ctRes.Decrypt() if err != nil || res.Uint64() != expected.Uint64() { t.Fatalf("%d != %d", expected.Uint64(), res.Uint64()) } @@ -373,10 +373,10 @@ func TfheScalarDiv(t *testing.T, fheUintType FheUintType) { b.SetUint64(1337) } expected := new(big.Int).Div(&a, &b) - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctRes, _ := ctA.scalarDiv(b.Uint64()) - res, err := ctRes.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctRes, _ := ctA.ScalarDiv(b.Uint64()) + res, err := ctRes.Decrypt() if err != nil || res.Uint64() != expected.Uint64() { t.Fatalf("%d != %d", expected.Uint64(), res.Uint64()) } @@ -399,10 +399,10 @@ func TfheScalarRem(t *testing.T, fheUintType FheUintType) { b.SetUint64(1337) } expected := new(big.Int).Rem(&a, &b) - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctRes, _ := ctA.scalarRem(b.Uint64()) - res, err := ctRes.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctRes, _ := ctA.ScalarRem(b.Uint64()) + res, err := ctRes.Decrypt() if err != nil || res.Uint64() != expected.Uint64() { t.Fatalf("%d != %d", expected.Uint64(), res.Uint64()) } @@ -425,12 +425,12 @@ func TfheBitAnd(t *testing.T, fheUintType FheUintType) { b.SetUint64(1337) } expected := a.Uint64() & b.Uint64() - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctB := new(tfheCiphertext) - ctB.encrypt(b, fheUintType) - ctRes, _ := ctA.bitand(ctB) - res, err := ctRes.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctB := new(TfheCiphertext) + ctB.Encrypt(b, fheUintType) + ctRes, _ := ctA.Bitand(ctB) + res, err := ctRes.Decrypt() if err != nil || res.Uint64() != expected { t.Fatalf("%d != %d", expected, res.Uint64()) } @@ -453,12 +453,12 @@ func TfheBitOr(t *testing.T, fheUintType FheUintType) { b.SetUint64(1337) } expected := a.Uint64() | b.Uint64() - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctB := new(tfheCiphertext) - ctB.encrypt(b, fheUintType) - ctRes, _ := ctA.bitor(ctB) - res, err := ctRes.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctB := new(TfheCiphertext) + ctB.Encrypt(b, fheUintType) + ctRes, _ := ctA.Bitor(ctB) + res, err := ctRes.Decrypt() if err != nil || res.Uint64() != expected { t.Fatalf("%d != %d", expected, res.Uint64()) } @@ -481,12 +481,12 @@ func TfheBitXor(t *testing.T, fheUintType FheUintType) { b.SetUint64(1337) } expected := a.Uint64() ^ b.Uint64() - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctB := new(tfheCiphertext) - ctB.encrypt(b, fheUintType) - ctRes, _ := ctA.bitxor(ctB) - res, err := ctRes.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctB := new(TfheCiphertext) + ctB.Encrypt(b, fheUintType) + ctRes, _ := ctA.Bitxor(ctB) + res, err := ctRes.Decrypt() if err != nil || res.Uint64() != expected { t.Fatalf("%d != %d", expected, res.Uint64()) } @@ -509,12 +509,12 @@ func TfheShl(t *testing.T, fheUintType FheUintType) { b.SetUint64(45) } expected := new(big.Int).Lsh(&a, uint(b.Uint64())) - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctB := new(tfheCiphertext) - ctB.encrypt(b, fheUintType) - ctRes, _ := ctA.shl(ctB) - res, err := ctRes.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctB := new(TfheCiphertext) + ctB.Encrypt(b, fheUintType) + ctRes, _ := ctA.Shl(ctB) + res, err := ctRes.Decrypt() if err != nil || res.Uint64() != expected.Uint64() { t.Fatalf("%d != %d", expected.Uint64(), res.Uint64()) } @@ -537,10 +537,10 @@ func TfheScalarShl(t *testing.T, fheUintType FheUintType) { b.SetUint64(45) } expected := new(big.Int).Lsh(&a, uint(b.Uint64())) - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctRes, _ := ctA.scalarShl(b.Uint64()) - res, err := ctRes.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctRes, _ := ctA.ScalarShl(b.Uint64()) + res, err := ctRes.Decrypt() if err != nil || res.Uint64() != expected.Uint64() { t.Fatalf("%d != %d", expected.Uint64(), res.Uint64()) } @@ -563,12 +563,12 @@ func TfheShr(t *testing.T, fheUintType FheUintType) { b.SetUint64(1337) } expected := new(big.Int).Rsh(&a, uint(b.Uint64())) - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctB := new(tfheCiphertext) - ctB.encrypt(b, fheUintType) - ctRes, _ := ctA.shr(ctB) - res, err := ctRes.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctB := new(TfheCiphertext) + ctB.Encrypt(b, fheUintType) + ctRes, _ := ctA.Shr(ctB) + res, err := ctRes.Decrypt() if err != nil || res.Uint64() != expected.Uint64() { t.Fatalf("%d != %d", expected.Uint64(), res.Uint64()) } @@ -591,10 +591,10 @@ func TfheScalarShr(t *testing.T, fheUintType FheUintType) { b.SetUint64(1337) } expected := new(big.Int).Rsh(&a, uint(b.Uint64())) - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctRes, _ := ctA.scalarShr(b.Uint64()) - res, err := ctRes.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctRes, _ := ctA.ScalarShr(b.Uint64()) + res, err := ctRes.Decrypt() if err != nil || res.Uint64() != expected.Uint64() { t.Fatalf("%d != %d", expected.Uint64(), res.Uint64()) } @@ -623,12 +623,12 @@ func TfheEq(t *testing.T, fheUintType FheUintType) { } else { expected = 0 } - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctB := new(tfheCiphertext) - ctB.encrypt(b, fheUintType) - ctRes, _ := ctA.eq(ctB) - res, err := ctRes.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctB := new(TfheCiphertext) + ctB.Encrypt(b, fheUintType) + ctRes, _ := ctA.Eq(ctB) + res, err := ctRes.Decrypt() if err != nil || res.Uint64() != expected { t.Fatalf("%d != %d", expected, res.Uint64()) } @@ -657,10 +657,10 @@ func TfheScalarEq(t *testing.T, fheUintType FheUintType) { } else { expected = 0 } - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctRes, _ := ctA.scalarEq(b.Uint64()) - res, err := ctRes.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctRes, _ := ctA.ScalarEq(b.Uint64()) + res, err := ctRes.Decrypt() if err != nil || res.Uint64() != expected { t.Fatalf("%d != %d", expected, res.Uint64()) } @@ -689,12 +689,12 @@ func TfheNe(t *testing.T, fheUintType FheUintType) { } else { expected = 0 } - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctB := new(tfheCiphertext) - ctB.encrypt(b, fheUintType) - ctRes, _ := ctA.ne(ctB) - res, err := ctRes.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctB := new(TfheCiphertext) + ctB.Encrypt(b, fheUintType) + ctRes, _ := ctA.Ne(ctB) + res, err := ctRes.Decrypt() if err != nil || res.Uint64() != expected { t.Fatalf("%d != %d", expected, res.Uint64()) } @@ -723,10 +723,10 @@ func TfheScalarNe(t *testing.T, fheUintType FheUintType) { } else { expected = 0 } - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctRes, _ := ctA.scalarNe(b.Uint64()) - res, err := ctRes.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctRes, _ := ctA.ScalarNe(b.Uint64()) + res, err := ctRes.Decrypt() if err != nil || res.Uint64() != expected { t.Fatalf("%d != %d", expected, res.Uint64()) } @@ -748,14 +748,14 @@ func TfheGe(t *testing.T, fheUintType FheUintType) { a.SetUint64(13371337) b.SetUint64(1337) } - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctB := new(tfheCiphertext) - ctB.encrypt(b, fheUintType) - ctRes1, _ := ctA.ge(ctB) - ctRes2, _ := ctB.ge(ctA) - res1, err1 := ctRes1.decrypt() - res2, err2 := ctRes2.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctB := new(TfheCiphertext) + ctB.Encrypt(b, fheUintType) + ctRes1, _ := ctA.Ge(ctB) + ctRes2, _ := ctB.Ge(ctA) + res1, err1 := ctRes1.Decrypt() + res2, err2 := ctRes2.Decrypt() if err1 != nil || res1.Uint64() != 1 { t.Fatalf("%d != %d", 1, res1.Uint64()) } @@ -780,10 +780,10 @@ func TfheScalarGe(t *testing.T, fheUintType FheUintType) { a.SetUint64(13371337) b.SetUint64(1337) } - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctRes1, _ := ctA.scalarGe(b.Uint64()) - res1, err := ctRes1.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctRes1, _ := ctA.ScalarGe(b.Uint64()) + res1, err := ctRes1.Decrypt() if err != nil || res1.Uint64() != 1 { t.Fatalf("%d != %d", 0, res1.Uint64()) } @@ -805,14 +805,14 @@ func TfheGt(t *testing.T, fheUintType FheUintType) { a.SetUint64(13371337) b.SetUint64(1337) } - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctB := new(tfheCiphertext) - ctB.encrypt(b, fheUintType) - ctRes1, _ := ctA.gt(ctB) - ctRes2, _ := ctB.gt(ctA) - res1, err1 := ctRes1.decrypt() - res2, err2 := ctRes2.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctB := new(TfheCiphertext) + ctB.Encrypt(b, fheUintType) + ctRes1, _ := ctA.Gt(ctB) + ctRes2, _ := ctB.Gt(ctA) + res1, err1 := ctRes1.Decrypt() + res2, err2 := ctRes2.Decrypt() if err1 != nil || res1.Uint64() != 1 { t.Fatalf("%d != %d", 0, res1.Uint64()) } @@ -837,10 +837,10 @@ func TfheScalarGt(t *testing.T, fheUintType FheUintType) { a.SetUint64(13371337) b.SetUint64(1337) } - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctRes1, _ := ctA.scalarGt(b.Uint64()) - res1, err := ctRes1.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctRes1, _ := ctA.ScalarGt(b.Uint64()) + res1, err := ctRes1.Decrypt() if err != nil || res1.Uint64() != 1 { t.Fatalf("%d != %d", 0, res1.Uint64()) } @@ -862,14 +862,14 @@ func TfheLe(t *testing.T, fheUintType FheUintType) { a.SetUint64(13371337) b.SetUint64(1337) } - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctB := new(tfheCiphertext) - ctB.encrypt(b, fheUintType) - ctRes1, _ := ctA.le(ctB) - ctRes2, _ := ctB.le(ctA) - res1, err1 := ctRes1.decrypt() - res2, err2 := ctRes2.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctB := new(TfheCiphertext) + ctB.Encrypt(b, fheUintType) + ctRes1, _ := ctA.Le(ctB) + ctRes2, _ := ctB.Le(ctA) + res1, err1 := ctRes1.Decrypt() + res2, err2 := ctRes2.Decrypt() if err1 != nil || res1.Uint64() != 0 { t.Fatalf("%d != %d", 0, res1.Uint64()) } @@ -894,10 +894,10 @@ func TfheScalarLe(t *testing.T, fheUintType FheUintType) { a.SetUint64(13371337) b.SetUint64(1337) } - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctRes1, _ := ctA.scalarLe(b.Uint64()) - res1, err := ctRes1.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctRes1, _ := ctA.ScalarLe(b.Uint64()) + res1, err := ctRes1.Decrypt() if err != nil || res1.Uint64() != 0 { t.Fatalf("%d != %d", 0, res1.Uint64()) } @@ -919,14 +919,14 @@ func TfheLt(t *testing.T, fheUintType FheUintType) { a.SetUint64(13371337) b.SetUint64(1337) } - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctB := new(tfheCiphertext) - ctB.encrypt(b, fheUintType) - ctRes1, _ := ctA.lt(ctB) - ctRes2, _ := ctB.lt(ctA) - res1, err1 := ctRes1.decrypt() - res2, err2 := ctRes2.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctB := new(TfheCiphertext) + ctB.Encrypt(b, fheUintType) + ctRes1, _ := ctA.Lt(ctB) + ctRes2, _ := ctB.Lt(ctA) + res1, err1 := ctRes1.Decrypt() + res2, err2 := ctRes2.Decrypt() if err1 != nil || res1.Uint64() != 0 { t.Fatalf("%d != %d", 0, res1.Uint64()) } @@ -951,10 +951,10 @@ func TfheScalarLt(t *testing.T, fheUintType FheUintType) { a.SetUint64(13371337) b.SetUint64(1337) } - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctRes1, _ := ctA.scalarLt(b.Uint64()) - res1, err := ctRes1.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctRes1, _ := ctA.ScalarLt(b.Uint64()) + res1, err := ctRes1.Decrypt() if err != nil || res1.Uint64() != 0 { t.Fatalf("%d != %d", 0, res1.Uint64()) } @@ -976,14 +976,14 @@ func TfheMin(t *testing.T, fheUintType FheUintType) { a.SetUint64(13371337) b.SetUint64(1337) } - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctB := new(tfheCiphertext) - ctB.encrypt(b, fheUintType) - ctRes1, _ := ctA.min(ctB) - ctRes2, _ := ctB.min(ctA) - res1, err1 := ctRes1.decrypt() - res2, err2 := ctRes2.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctB := new(TfheCiphertext) + ctB.Encrypt(b, fheUintType) + ctRes1, _ := ctA.Min(ctB) + ctRes2, _ := ctB.Min(ctA) + res1, err1 := ctRes1.Decrypt() + res2, err2 := ctRes2.Decrypt() if err1 != nil || res1.Uint64() != b.Uint64() { t.Fatalf("%d != %d", b.Uint64(), res1.Uint64()) } @@ -1008,10 +1008,10 @@ func TfheScalarMin(t *testing.T, fheUintType FheUintType) { a.SetUint64(13371337) b.SetUint64(1337) } - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctRes1, _ := ctA.scalarMin(b.Uint64()) - res1, err1 := ctRes1.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctRes1, _ := ctA.ScalarMin(b.Uint64()) + res1, err1 := ctRes1.Decrypt() if err1 != nil || res1.Uint64() != b.Uint64() { t.Fatalf("%d != %d", 0, res1.Uint64()) } @@ -1033,14 +1033,14 @@ func TfheMax(t *testing.T, fheUintType FheUintType) { a.SetUint64(13371337) b.SetUint64(1337) } - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctB := new(tfheCiphertext) - ctB.encrypt(b, fheUintType) - ctRes1, _ := ctA.max(ctB) - ctRes2, _ := ctB.max(ctA) - res1, err1 := ctRes1.decrypt() - res2, err2 := ctRes2.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctB := new(TfheCiphertext) + ctB.Encrypt(b, fheUintType) + ctRes1, _ := ctA.Max(ctB) + ctRes2, _ := ctB.Max(ctA) + res1, err1 := ctRes1.Decrypt() + res2, err2 := ctRes2.Decrypt() if err1 != nil || res1.Uint64() != a.Uint64() { t.Fatalf("%d != %d", b.Uint64(), res1.Uint64()) } @@ -1065,10 +1065,10 @@ func TfheScalarMax(t *testing.T, fheUintType FheUintType) { a.SetUint64(13371337) b.SetUint64(1337) } - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctRes1, _ := ctA.scalarMax(b.Uint64()) - res1, err1 := ctRes1.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctRes1, _ := ctA.ScalarMax(b.Uint64()) + res1, err1 := ctRes1.Decrypt() if err1 != nil || res1.Uint64() != a.Uint64() { t.Fatalf("%d != %d", 0, res1.Uint64()) } @@ -1092,10 +1092,10 @@ func TfheNeg(t *testing.T, fheUintType FheUintType) { a.SetUint64(13333377777777777) expected = uint64(-uint64(a.Uint64())) } - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctRes1, _ := ctA.neg() - res1, err1 := ctRes1.decrypt() + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctRes1, _ := ctA.Neg() + res1, err1 := ctRes1.Decrypt() if err1 != nil || res1.Uint64() != expected { t.Fatalf("%d != %d", res1.Uint64(), expected) } @@ -1118,11 +1118,11 @@ func TfheNot(t *testing.T, fheUintType FheUintType) { a.SetUint64(13333377777777777) expected = uint64(^uint64(a.Uint64())) } - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) - ctRes1, _ := ctA.not() - res1, err1 := ctRes1.decrypt() + ctRes1, _ := ctA.Not() + res1, err1 := ctRes1.Decrypt() if err1 != nil || res1.Uint64() != expected { t.Fatalf("%d != %d", res1.Uint64(), expected) } @@ -1146,18 +1146,18 @@ func TfheIfThenElse(t *testing.T, fheUintType FheUintType) { a.SetUint64(13333377777777777) b.SetUint64(133337) } - ctCondition := new(tfheCiphertext) - ctCondition.encrypt(condition, fheUintType) - ctCondition2 := new(tfheCiphertext) - ctCondition2.encrypt(condition2, fheUintType) - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintType) - ctB := new(tfheCiphertext) - ctB.encrypt(b, fheUintType) - ctRes1, _ := ctCondition.ifThenElse(ctA, ctB) - ctRes2, _ := ctCondition2.ifThenElse(ctA, ctB) - res1, err1 := ctRes1.decrypt() - res2, err2 := ctRes2.decrypt() + ctCondition := new(TfheCiphertext) + ctCondition.Encrypt(condition, fheUintType) + ctCondition2 := new(TfheCiphertext) + ctCondition2.Encrypt(condition2, fheUintType) + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintType) + ctB := new(TfheCiphertext) + ctB.Encrypt(b, fheUintType) + ctRes1, _ := ctCondition.IfThenElse(ctA, ctB) + ctRes2, _ := ctCondition2.IfThenElse(ctA, ctB) + res1, err1 := ctRes1.Decrypt() + res2, err2 := ctRes2.Decrypt() if err1 != nil || res1.Uint64() != a.Uint64() { t.Fatalf("%d != %d", 0, res1.Uint64()) } @@ -1191,9 +1191,9 @@ func TfheCast(t *testing.T, fheUintTypeFrom FheUintType, fheUintTypeTo FheUintTy modulus = uint64(math.Pow(2, 64)) } - ctA := new(tfheCiphertext) - ctA.encrypt(a, fheUintTypeFrom) - ctRes, err := ctA.castTo(fheUintTypeTo) + ctA := new(TfheCiphertext) + ctA.Encrypt(a, fheUintTypeFrom) + ctRes, err := ctA.CastTo(fheUintTypeTo) if err != nil { t.Fatal(err) } @@ -1201,7 +1201,7 @@ func TfheCast(t *testing.T, fheUintTypeFrom FheUintType, fheUintTypeTo FheUintTy if ctRes.fheUintType != fheUintTypeTo { t.Fatalf("type %d != type %d", ctA.fheUintType, fheUintTypeTo) } - res, err := ctRes.decrypt() + res, err := ctRes.Decrypt() expected := a.Uint64() % modulus if err != nil || res.Uint64() != expected { t.Fatalf("%d != %d", res.Uint64(), expected) diff --git a/fhevm/tfhe_wrappers.go b/fhevm/tfhe_wrappers.go index d14adf8..bfb2f89 100644 --- a/fhevm/tfhe_wrappers.go +++ b/fhevm/tfhe_wrappers.go @@ -47,10 +47,12 @@ func serialize(ptr unsafe.Pointer, t FheUintType) ([]byte, error) { return ser, nil } -func serializePublicKey(pks unsafe.Pointer) ([]byte, error) { +func serializePublicKey() ([]byte, error) { + if pks == nil { + return nil, errors.New("serialize: no public key available") + } out := &C.DynamicBuffer{} - var ret C.int - ret = C.serialize_compact_public_key(pks, out) + ret := C.serialize_compact_public_key(pks, out) if ret != 0 { return nil, errors.New("serialize: failed to serialize public key") } @@ -59,13 +61,6 @@ func serializePublicKey(pks unsafe.Pointer) ([]byte, error) { return ser, nil } -func isValidType(t byte) bool { - if uint8(t) < uint8(FheUint8) || uint8(t) > uint8(FheUint64) { - return false - } - return true -} - func encryptAndSerializeCompact(value uint64, fheUintType FheUintType) []byte { out := &C.DynamicBuffer{} switch fheUintType {