From b50b7d0b7b09616e13bcf74aaf3a2ec2080f8466 Mon Sep 17 00:00:00 2001 From: LoveNoble Date: Tue, 28 May 2024 15:26:28 +0200 Subject: [PATCH 1/5] fibitwise operations for uint4 type --- fhevm/tee_bit.go | 6 +++--- fhevm/tee_bit_test.go | 6 +++--- fhevm/tee_crypto_test.go | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/fhevm/tee_bit.go b/fhevm/tee_bit.go index 0025cb7..b3d8730 100644 --- a/fhevm/tee_bit.go +++ b/fhevm/tee_bit.go @@ -14,7 +14,7 @@ func teeShlRun(environment EVMEnvironment, caller common.Address, addr common.Ad // There isn't bitwise shift operation between ebool. So it doesn't include case 0. case tfhe.FheUint4: a1, b1 := uint8(a), uint8(b)%4 - return uint64(a1 << b1), nil + return uint64(a1<> (uint8(4) - b1))), nil + return uint64((a1<>(uint8(4)-b1))) & 0x0F, nil case tfhe.FheUint8: a1, b1 := uint8(a), uint8(b)%8 return uint64((a1 << b1) | (a1 >> (uint8(8) - b1))), nil @@ -94,7 +94,7 @@ func teeRotrRun(environment EVMEnvironment, caller common.Address, addr common.A // There isn't bitwise shift operation between ebool. So it doesn't include case 0. case tfhe.FheUint4: a1, b1 := uint8(a), uint8(b)%4 - return uint64((a1 >> b1) | (a1 << (uint8(4) - b1))), nil + return uint64((a1>>b1)|(a1<<(uint8(4)-b1))) & 0x0F, nil case tfhe.FheUint8: a1, b1 := uint8(a), uint8(b)%8 return uint64((a1 >> b1) | (a1 << (uint8(8) - b1))), nil diff --git a/fhevm/tee_bit_test.go b/fhevm/tee_bit_test.go index 2637edc..38502f9 100644 --- a/fhevm/tee_bit_test.go +++ b/fhevm/tee_bit_test.go @@ -88,7 +88,7 @@ func TestTeeRotrRun(t *testing.T) { rhs uint64 expected uint64 }{ - {tfhe.FheUint4, 2, 1, 17}, + {tfhe.FheUint4, 2, 1, 1}, {tfhe.FheUint8, 4, 2, 1}, {tfhe.FheUint16, 4283, 3, 25111}, {tfhe.FheUint32, 1333337, 10, 373294358}, @@ -186,7 +186,7 @@ func TestTeeNegRun(t *testing.T) { chs uint64 expected uint64 }{ - {tfhe.FheUint4, 2, 254}, + {tfhe.FheUint4, 2, 14}, {tfhe.FheUint8, 2, 254}, {tfhe.FheUint16, 4283, 61253}, {tfhe.FheUint32, 1333337, 4293633959}, @@ -207,7 +207,7 @@ func TestTeeNotRun(t *testing.T) { chs uint64 expected uint64 }{ - {tfhe.FheUint4, 2, 253}, + {tfhe.FheUint4, 2, 13}, {tfhe.FheUint8, 2, 253}, {tfhe.FheUint16, 4283, 61252}, {tfhe.FheUint32, 1333337, 4293633958}, diff --git a/fhevm/tee_crypto_test.go b/fhevm/tee_crypto_test.go index bc441f2..798d611 100644 --- a/fhevm/tee_crypto_test.go +++ b/fhevm/tee_crypto_test.go @@ -16,7 +16,7 @@ func TestTeeDecryptRun(t *testing.T) { typ tfhe.FheUintType expected uint64 }{ - {tfhe.FheUint4, uint64(rapid.Uint8().Draw(t, "expected"))}, + {tfhe.FheUint4, uint64(rapid.Uint8Range(0, 15).Draw(t, "expected"))}, {tfhe.FheUint8, uint64(rapid.Uint8().Draw(t, "expected"))}, {tfhe.FheUint16, uint64(rapid.Uint16().Draw(t, "expected"))}, {tfhe.FheUint32, uint64(rapid.Uint32().Draw(t, "expected"))}, From e9af8856a912a5f5b12bcbe87dbd8f08534d974f Mon Sep 17 00:00:00 2001 From: LoveNoble Date: Mon, 3 Jun 2024 21:52:41 +0200 Subject: [PATCH 2/5] fix: fix the bug in teeSelect --- fhevm/tee_comparison.go | 11 +++++++++-- fhevm/tee_comparison_test.go | 6 ++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/fhevm/tee_comparison.go b/fhevm/tee_comparison.go index 4d5cf5b..c777a4e 100644 --- a/fhevm/tee_comparison.go +++ b/fhevm/tee_comparison.go @@ -1,6 +1,7 @@ package fhevm import ( + "errors" "fmt" "math/big" @@ -77,7 +78,7 @@ func teeMaxRun(environment EVMEnvironment, caller common.Address, addr common.Ad func teeSelectRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool, runSpan trace.Span) ([]byte, error) { logger := environment.GetLogger() - p1, p2, _, h1, h2, h3, err := extract3Operands("teeSelect", environment, input, runSpan) + p1, p2, p3, h1, h2, h3, err := extract3Operands("teeSelect", environment, input, runSpan) if err != nil { logger.Error("teeSelect", "failed", "err", err) return nil, err @@ -88,6 +89,12 @@ func teeSelectRun(environment EVMEnvironment, caller common.Address, addr common return importRandomCiphertext(environment, p2.FheUintType), nil } + if h2.fheUintType() != h3.fheUintType() { + msg := "fheIfThenElse operand type mismatch" + logger.Error(msg, "second", h2.fheUintType(), "third", h3.fheUintType()) + return nil, errors.New(msg) + } + // TODO ref: https://github.com/Inco-fhevm/inco-monorepo/issues/6 if p2.FheUintType == tfhe.FheUint128 { // panic("TODO implement me") @@ -103,7 +110,7 @@ func teeSelectRun(environment EVMEnvironment, caller common.Address, addr common // result back to the FheUintType. var result big.Int s := big.NewInt(0).SetBytes(p2.Value) - t := big.NewInt(0).SetBytes(p2.Value) + t := big.NewInt(0).SetBytes(p3.Value) if p1.Value[0] == 1 { result.Set(s) } else { diff --git a/fhevm/tee_comparison_test.go b/fhevm/tee_comparison_test.go index 1866812..68302df 100644 --- a/fhevm/tee_comparison_test.go +++ b/fhevm/tee_comparison_test.go @@ -227,6 +227,12 @@ func TestTeeSelectRun(t *testing.T) { {tfhe.FheUint32, true, big.NewInt(1333337), big.NewInt(1337), big.NewInt(1333337)}, {tfhe.FheUint64, true, big.NewInt(13333377777777777), big.NewInt(133377777777), big.NewInt(13333377777777777)}, {tfhe.FheUint160, true, a, b, a}, + {tfhe.FheUint4, false, big.NewInt(2), big.NewInt(1), big.NewInt(1)}, + {tfhe.FheUint8, false, big.NewInt(2), big.NewInt(1), big.NewInt(1)}, + {tfhe.FheUint16, false, big.NewInt(4283), big.NewInt(1337), big.NewInt(1337)}, + {tfhe.FheUint32, false, big.NewInt(1333337), big.NewInt(1337), big.NewInt(1337)}, + {tfhe.FheUint64, false, big.NewInt(13333377777777777), big.NewInt(133377777777), big.NewInt(133377777777)}, + {tfhe.FheUint160, false, a, b, b}, } for _, tc := range testcases { t.Run(fmt.Sprintf("teeSelect with %s", tc.typ), func(t *testing.T) { From 2aebb21f3aebc62604032f160a989c59522ec4c8 Mon Sep 17 00:00:00 2001 From: LoveNoble Date: Sun, 9 Jun 2024 08:04:26 +0200 Subject: [PATCH 3/5] fix: bug fixes on neg operation for bool type --- fhevm/tee_bit_gas.go | 27 +++++++++++++++++++++++++-- fhevm/tee_bit_test.go | 2 ++ fhevm/tee_interpreter.go | 11 ++++++++++- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/fhevm/tee_bit_gas.go b/fhevm/tee_bit_gas.go index faea930..2ddcd25 100644 --- a/fhevm/tee_bit_gas.go +++ b/fhevm/tee_bit_gas.go @@ -1,5 +1,12 @@ package fhevm +import ( + "encoding/hex" + + "github.com/ethereum/go-ethereum/common" + "github.com/zama-ai/fhevm-go/fhevm/tfhe" +) + func teeShiftRequiredGas(environment EVMEnvironment, suppliedGas uint64, input []byte) uint64 { return teeOperationGas("teeShift", environment, input, environment.FhevmParams().GasCosts.TeeShift) } @@ -9,9 +16,25 @@ func teeBitwiseOpRequiredGas(environment EVMEnvironment, suppliedGas uint64, inp } func teeNotRequiredGas(environment EVMEnvironment, suppliedGas uint64, input []byte) uint64 { - return teeOperationGas("teeNot", environment, input, environment.FhevmParams().GasCosts.TeeNot) + return teeUnaryOperationGas("teeNot", environment, input, environment.FhevmParams().GasCosts.TeeNot) } func teeNegRequiredGas(environment EVMEnvironment, suppliedGas uint64, input []byte) uint64 { - return teeOperationGas("teeNeg", environment, input, environment.FhevmParams().GasCosts.TeeNeg) + return teeUnaryOperationGas("teeNeg", environment, input, environment.FhevmParams().GasCosts.TeeNeg) +} + +func teeUnaryOperationGas(_ string, environment EVMEnvironment, input []byte, gasCosts map[tfhe.FheUintType]uint64) uint64 { + input = input[:minInt(32, len(input))] + + logger := environment.GetLogger() + if len(input) != 32 { + logger.Error("teeNeg 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("teeNeg input not verified", "input", hex.EncodeToString(input)) + return 0 + } + return gasCosts[ct.fheUintType()] } diff --git a/fhevm/tee_bit_test.go b/fhevm/tee_bit_test.go index 38502f9..7bda37c 100644 --- a/fhevm/tee_bit_test.go +++ b/fhevm/tee_bit_test.go @@ -212,6 +212,8 @@ func TestTeeNotRun(t *testing.T) { {tfhe.FheUint16, 4283, 61252}, {tfhe.FheUint32, 1333337, 4293633958}, {tfhe.FheUint64, 13333377777777777, 18433410695931773838}, + {tfhe.FheBool, 1, 0}, + {tfhe.FheBool, 0, 1}, } for _, tc := range testcases { t.Run(fmt.Sprintf("teeNot with %s", tc.typ), func(t *testing.T) { diff --git a/fhevm/tee_interpreter.go b/fhevm/tee_interpreter.go index 186b6ef..aa302c6 100644 --- a/fhevm/tee_interpreter.go +++ b/fhevm/tee_interpreter.go @@ -249,7 +249,16 @@ func doNegNotOp( // result back to the FheUintType. c := big.NewInt(0).SetBytes(cp.Value).Uint64() - result := operator(c) + var result uint64 + if cp.FheUintType == tfhe.FheBool { + if c == 0 { + result = 1 + } else { + result = 0 + } + } else { + result = operator(c) + } var resultBz []byte resultBz, err = marshalTfheType(result, cp.FheUintType) From 0de4c027f296852e0871bff97e217af3fed947aa Mon Sep 17 00:00:00 2001 From: LoveNoble Date: Sun, 9 Jun 2024 08:04:55 +0200 Subject: [PATCH 4/5] fix: bug fixes on comparison operator --- fhevm/tee_comparison.go | 2 +- fhevm/tee_comparison_gas.go | 28 ++++++++++++++++++++++++++++ fhevm/teelib.go | 2 +- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/fhevm/tee_comparison.go b/fhevm/tee_comparison.go index c777a4e..1ff89d2 100644 --- a/fhevm/tee_comparison.go +++ b/fhevm/tee_comparison.go @@ -111,7 +111,7 @@ func teeSelectRun(environment EVMEnvironment, caller common.Address, addr common var result big.Int s := big.NewInt(0).SetBytes(p2.Value) t := big.NewInt(0).SetBytes(p3.Value) - if p1.Value[0] == 1 { + if p1.Value[len(p1.Value)-1] == 1 { result.Set(s) } else { result.Set(t) diff --git a/fhevm/tee_comparison_gas.go b/fhevm/tee_comparison_gas.go index 95ba2a5..2f424b7 100644 --- a/fhevm/tee_comparison_gas.go +++ b/fhevm/tee_comparison_gas.go @@ -1,5 +1,33 @@ package fhevm +import ( + "encoding/hex" + + "github.com/zama-ai/fhevm-go/fhevm/tfhe" +) + func teeComparisonRequiredGas(environment EVMEnvironment, suppliedGas uint64, input []byte) uint64 { return teeOperationGas("teeComparison", environment, input, environment.FhevmParams().GasCosts.TeeComparison) } + +func teeSelectRequiredGas(environment EVMEnvironment, suppliedGas uint64, input []byte) uint64 { + input = input[:minInt(96, len(input))] + + logger := environment.GetLogger() + + first, second, third, err := get3VerifiedOperands(environment, input) + if err != nil { + logger.Error("teeSelect op RequiredGas() inputs not verified", "err", err, "input", hex.EncodeToString(input)) + return 0 + } + if first.fheUintType() != tfhe.FheBool { + logger.Error("teeSelect op RequiredGas() invalid type for condition", "first", first.fheUintType()) + return 0 + } + if second.fheUintType() != third.fheUintType() { + logger.Error("teeSelect op RequiredGas() operand type mismatch", "second", second.fheUintType(), "third", third.fheUintType()) + return 0 + } + + return environment.FhevmParams().GasCosts.TeeComparison[second.fheUintType()] +} diff --git a/fhevm/teelib.go b/fhevm/teelib.go index 85e155b..61f3f22 100644 --- a/fhevm/teelib.go +++ b/fhevm/teelib.go @@ -104,7 +104,7 @@ var teelibMethods = []*FheLibMethod{ { name: "teeSelect", argTypes: "(uint256,uint256,uint256)", - requiredGasFunction: teeComparisonRequiredGas, + requiredGasFunction: teeSelectRequiredGas, runFunction: teeSelectRun, }, { From 5461147ec41a6d2e2bc594f06e43d5966fe9f160 Mon Sep 17 00:00:00 2001 From: LoveNoble Date: Sun, 9 Jun 2024 08:05:35 +0200 Subject: [PATCH 5/5] fix: bug in asUint8 function --- tee/tee_mock.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tee/tee_mock.go b/tee/tee_mock.go index 8b59065..3cf2646 100644 --- a/tee/tee_mock.go +++ b/tee/tee_mock.go @@ -48,7 +48,7 @@ func (sp TeePlaintext) AsUint8() uint8 { panic(fmt.Sprintf("Expected FheUint4 or FheUint8, got %s", sp.FheUintType)) } - return sp.Value[0] + return sp.Value[len(sp.Value)-1] } // AsUint16 returns the plaintext as a uint16.