From cda5c9f42c13513851077a110852b22f48ef95f4 Mon Sep 17 00:00:00 2001 From: Petar Ivanov <29689712+dartdart26@users.noreply.github.com> Date: Wed, 12 Jun 2024 18:54:06 +0300 Subject: [PATCH] feat: size-efficient list-based ciphertext inputs Add support for list-based ciphertext inputs. Two types are supported: * CompactFheUint160List * CompactFheUint2048List No other input types are supported. Instead, the `fhevmjs` library encodes any type other than the FheUint2048 type as FheUint160. In fhevm-go during ciphertext verification, we cast it homomorphically to the requested data type. FheUint2048 values are expanded as is, without any casts. The API of the verifyCiphertext precompile changes such that now it accepts two inputs (through TFHE.asEuintXX() library function in fhevm): * bytes32 Handle * serialized compact FHE list Handle format changes and is no longer the hash of the expanded ciphertext. Instead, input handles have the following format: * byte 0 to 28: first 29 bytes of keccak256(serialized compact FHE list) * byte 29: index in the serialized compact FHE list (0-indexed) * byte 30: type of the ciphertext * byte 31: version Non-input handles have the following format: * byte 0 to 29: first 30 bytes of keccak256(serialized compact FHE list) * byte 30: type of the ciphertext * byte 31: version Above allows us to pack multiple inputs in one or more CompactFheUint160Lists. Add support for equality and non-equality of FheUint2048 values. Cleanup should be done in a future commit in order to remove unused code, duplication and to simplify the implementation and the tests, especially around tfhe-rs handling. --- fhevm/ciphertext_storage.go | 22 +- fhevm/contracts_test.go | 454 ++++++++++++++++++------------ fhevm/evm.go | 2 +- fhevm/fhelib.go | 2 +- fhevm/instructions.go | 2 +- fhevm/interface.go | 3 + fhevm/operators_arithmetic.go | 32 +-- fhevm/operators_bit.go | 52 ++-- fhevm/operators_comparison.go | 70 ++--- fhevm/operators_crypto.go | 198 +++++++++---- fhevm/operators_crypto_gas.go | 10 +- fhevm/operators_rand.go | 6 +- fhevm/tfhe/tfhe_ciphertext.go | 240 +++++++++++++--- fhevm/tfhe/tfhe_key_management.go | 18 +- fhevm/tfhe/tfhe_test.go | 85 ++++++ fhevm/tfhe/tfhe_wrappers.c | 178 +++++++++++- fhevm/tfhe/tfhe_wrappers.go | 242 +++++++++++++++- fhevm/tfhe/tfhe_wrappers.h | 38 ++- tfhe-rs | 2 +- 19 files changed, 1253 insertions(+), 403 deletions(-) diff --git a/fhevm/ciphertext_storage.go b/fhevm/ciphertext_storage.go index 87888a7..747ecce 100644 --- a/fhevm/ciphertext_storage.go +++ b/fhevm/ciphertext_storage.go @@ -63,7 +63,7 @@ func loadCiphertextMetadata(env EVMEnvironment, handle common.Hash) *ciphertextM return newCiphertextMetadata(metadataInt.Bytes32()) } -// Returns the ciphertext for the given `handle“ and the gas needed to laod the ciphertext. +// Returns the ciphertext for the given `handle` and the gas needed to laod the ciphertext. // Returned gas would be zero if already loaded to memory. // If `handle` doesn't point to a ciphertext or an error occurs, (nil, 0) is returned. func loadCiphertext(env EVMEnvironment, handle common.Hash) (ct *tfhe.TfheCiphertext, gas uint64) { @@ -99,31 +99,31 @@ func loadCiphertext(env EVMEnvironment, handle common.Hash) (ct *tfhe.TfheCipher return ct, env.FhevmParams().GasCosts.FheStorageSloadGas[ct.Type()] } -func insertCiphertextToMemory(env EVMEnvironment, ct *tfhe.TfheCiphertext) { - env.FhevmData().loadedCiphertexts[ct.GetHash()] = ct +func insertCiphertextToMemory(env EVMEnvironment, handle common.Hash, ct *tfhe.TfheCiphertext) { + env.FhevmData().loadedCiphertexts[handle] = ct } // Persist the given ciphertext. -func persistCiphertext(env EVMEnvironment, ct *tfhe.TfheCiphertext) { +func persistCiphertext(env EVMEnvironment, handle common.Hash, ct *tfhe.TfheCiphertext) { logger := env.GetLogger() - if isCiphertextPersisted(env, ct.GetHash()) { + if isCiphertextPersisted(env, handle) { // Assuming a handle is a hash of the ciphertext, if metadata is already existing in storage it means the ciphertext is too. - logger.Info("ciphertext already persisted to storage", "handle", ct.GetHash().Hex()) + logger.Info("ciphertext already persisted to storage", "handle", handle.Hex()) return } metadata := ciphertextMetadata{} - metadata.length = uint64(tfhe.ExpandedFheCiphertextSize[ct.FheUintType]) - metadata.fheUintType = ct.FheUintType + metadata.length = uint64(tfhe.ExpandedFheCiphertextSize[ct.Type()]) + metadata.fheUintType = ct.Type() // Persist the metadata in storage. - env.SetState(ciphertextStorage, ct.GetHash(), metadata.serialize()) + env.SetState(ciphertextStorage, handle, metadata.serialize()) - ciphertextSlot := newInt(ct.GetHash().Bytes()) + ciphertextSlot := newInt(handle.Bytes()) ciphertextSlot.AddUint64(ciphertextSlot, 1) if env.IsCommitting() { logger.Info("persisting new ciphertext", - "handle", hex.EncodeToString(ct.GetHash().Bytes()), + "handle", hex.EncodeToString(handle.Bytes()), "type", metadata.fheUintType, "len", metadata.length, "ciphertextSlot", hex.EncodeToString(ciphertextSlot.Bytes())) diff --git a/fhevm/contracts_test.go b/fhevm/contracts_test.go index 3915722..14c95ef 100644 --- a/fhevm/contracts_test.go +++ b/fhevm/contracts_test.go @@ -3,13 +3,11 @@ package fhevm import ( "bytes" "context" - "encoding/binary" "encoding/hex" "errors" "fmt" "math/big" "os" - "strings" "testing" "github.com/ethereum/go-ethereum/common" @@ -238,12 +236,52 @@ 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 createInputList(values []big.Int, types []tfhe.FheUintType, listFheUintType tfhe.FheUintType) (handles [][32]byte, ciphertext []byte) { + if listFheUintType == tfhe.FheUint160 { + ciphertext, _ = tfhe.EncryptAndSerializeCompact160List(values) + } else if listFheUintType == tfhe.FheUint2048 { + ciphertext, _ = tfhe.EncryptAndSerializeCompact2048List(values) + } else { + panic("unsupported list type") + } + handles = make([][32]byte, 0) + for i := range types { + index := byte(i) + handle := crypto.Keccak256Hash(append(ciphertext, index)) + handle[29] = index + handle[30] = byte(types[i]) + handle[31] = 0 + handles = append(handles, handle) + } + return +} + +func createInputListWithBadIndex(values []big.Int, types []tfhe.FheUintType, listFheUintType tfhe.FheUintType) (handles [][32]byte, ciphertext []byte) { + if listFheUintType == tfhe.FheUint160 { + ciphertext, _ = tfhe.EncryptAndSerializeCompact160List(values) + } else if listFheUintType == tfhe.FheUint2048 { + panic("") + } else { + panic("unsupported list type") + } + handles = make([][32]byte, 0) + for i := range types { + index := byte(i + 25) + handle := crypto.Keccak256Hash(append(ciphertext, index)) + handle[29] = byte(i + 25) + handle[30] = byte(types[i]) + handle[31] = 0 + handles = append(handles, handle) + } + return +} + +func packInputList(handle [32]byte, ciphertext []byte, fheUintListType tfhe.FheUintType) []byte { + input, err := verifyCipertextMethod.Inputs.Pack(handle, [20]byte{}, ciphertext, [1]byte{byte(fheUintListType)}) + if err != nil { + panic(err) + } + return input } func loadCiphertextInTestMemory(environment EVMEnvironment, value uint64, depth int, t tfhe.FheUintType) *tfhe.TfheCiphertext { @@ -254,77 +292,213 @@ func loadCiphertextInTestMemory(environment EVMEnvironment, value uint64, depth if err != nil { panic(err) } - insertCiphertextToMemory(environment, ct) + insertCiphertextToMemory(environment, ct.GetHash(), ct) return ct } -func VerifyCiphertext(t *testing.T, fheUintType tfhe.FheUintType) { - var value uint64 - switch fheUintType { - case tfhe.FheBool: - value = 1 - case tfhe.FheUint4: - value = 4 - case tfhe.FheUint8: - value = 234 - case tfhe.FheUint16: - value = 4283 - case tfhe.FheUint32: - value = 1333337 - case tfhe.FheUint64: - value = 13333377777777777 - } +func VerifyCiphertextList(t *testing.T, listFheUintType tfhe.FheUintType, fheUintType tfhe.FheUintType) { depth := 1 environment := newTestEVMEnvironment() environment.depth = depth addr := tfheExecutorContractAddress readOnly := false - compact := tfhe.EncryptAndSerializeCompact(value, fheUintType) - input := prepareInputForVerifyCiphertext(append(compact, byte(fheUintType))) - out, err := verifyCiphertextRun(environment, addr, addr, input, readOnly, nil) + handles, ciphertext := createInputList([]big.Int{*big.NewInt(5), *big.NewInt(6)}, []tfhe.FheUintType{fheUintType, fheUintType}, listFheUintType) + handle1 := handles[0] + handle2 := handles[1] + + input1 := packInputList(handle1, ciphertext, listFheUintType) + out1, err := verifyCiphertextRun(environment, addr, addr, input1, readOnly, nil) if err != nil { t.Fatalf(err.Error()) } - ct := new(tfhe.TfheCiphertext) - if err = ct.DeserializeCompact(compact, fheUintType); err != nil { + input2 := packInputList(handle2, ciphertext, listFheUintType) + out2, err := verifyCiphertextRun(environment, addr, addr, input2, readOnly, nil) + if err != nil { t.Fatalf(err.Error()) } - if common.BytesToHash(out) != ct.GetHash() { - t.Fatalf("output hash in verifyCipertext is incorrect") + if len(environment.fhevmData.expandedInputCiphertexts) != 1 { + t.Fatalf("expected 1 input list ciphertext, got %d", len(environment.fhevmData.expandedInputCiphertexts)) } - res, _ := loadCiphertext(environment, ct.GetHash()) - if res == nil { + for _, expandedCiphertexts := range environment.fhevmData.expandedInputCiphertexts { + if len(expandedCiphertexts) != 2 { + t.Fatalf("expected 2 expanded ciphertexts, got %d", len(expandedCiphertexts)) + } + } + + if !bytes.Equal(out1, handle1[:]) { + t.Fatalf("output from verifyCipertext is not equal to input handle") + } + expanded1, _ := loadCiphertext(environment, handle1) + if expanded1 == nil { + t.Fatalf("verifyCiphertext must have verified given ciphertext") + } + if expanded1.Type() != fheUintType { + t.Fatalf("verifyCiphertext must have casted the expanded ciphertext of type %d to the requested type %d", expanded1.Type(), fheUintType) + } + decrypted1, err := expanded1.Decrypt() + if err != nil || !decrypted1.IsUint64() { + t.Fatalf("verifyCiphertext decrypted1 must be uint64") + } + if fheUintType == tfhe.FheBool { + if decrypted1.Uint64() == 0 { + t.Fatalf("verifyCiphertext decrypted1 value must be true") + } + } else if decrypted1.Uint64() != 5 { + t.Fatalf("verifyCiphertext decrypted1 value must be 5") + } + + if !bytes.Equal(out2, handle2[:]) { + t.Fatalf("output from verifyCipertext is not equal to input handle") + } + expanded2, _ := loadCiphertext(environment, handle2) + if expanded2 == nil { t.Fatalf("verifyCiphertext must have verified given ciphertext") } + if expanded2.Type() != fheUintType { + t.Fatalf("verifyCiphertext must have casted the expanded ciphertext of type %d to the requested type %d", expanded2.Type(), fheUintType) + } + decrypted2, err := expanded2.Decrypt() + if err != nil || !decrypted2.IsUint64() { + t.Fatalf("verifyCiphertext decrypted2 must be uint64") + } + if fheUintType == tfhe.FheBool { + if decrypted2.Uint64() == 0 { + t.Fatalf("verifyCiphertext decrypted2 value must be true") + } + } else if decrypted2.Uint64() != 6 { + t.Fatalf("verifyCiphertext decrypted2 value must be 6") + } } -func VerifyCiphertextBadType(t *testing.T, actualType tfhe.FheUintType, metadataType tfhe.FheUintType) { - var value uint64 - switch actualType { - case tfhe.FheUint4: - value = 2 - case tfhe.FheUint8: - value = 2 - case tfhe.FheUint16: - value = 4283 - case tfhe.FheUint32: - value = 1333337 - case tfhe.FheUint64: - value = 13333377777777777 +func TestVerifyCiphertextBadTypeIn2048List(t *testing.T) { + depth := 1 + environment := newTestEVMEnvironment() + environment.depth = depth + addr := tfheExecutorContractAddress + readOnly := false + handles, ciphertext := createInputList([]big.Int{*big.NewInt(42)}, []tfhe.FheUintType{tfhe.FheUint32}, tfhe.FheUint2048) + handle := handles[0] + input := packInputList(handle, ciphertext, tfhe.FheUint2048) + _, err := verifyCiphertextRun(environment, addr, addr, input, readOnly, nil) + if err == nil { + t.Fatalf("verifyCiphertext must have failed on unsupported type in 2048 list") } + if len(environment.fhevmData.expandedInputCiphertexts) != 0 { + t.Fatalf("expected 0 expanded input ciphertexts, got %d", len(environment.fhevmData.expandedInputCiphertexts)) + } + if len(environment.fhevmData.loadedCiphertexts) != 0 { + t.Fatalf("expected 0 loaded ciphertexts, got %d", len(environment.fhevmData.loadedCiphertexts)) + } +} + +func TestVerifyCiphertextUnsupportedListType(t *testing.T) { depth := 1 environment := newTestEVMEnvironment() environment.depth = depth addr := tfheExecutorContractAddress readOnly := false - compact := tfhe.EncryptAndSerializeCompact(value, actualType) - input := prepareInputForVerifyCiphertext(append(compact, byte(metadataType))) + handles, ciphertext := createInputList([]big.Int{*big.NewInt(42)}, []tfhe.FheUintType{tfhe.FheUint32}, tfhe.FheUint160) + handle := handles[0] + unsuportedType := tfhe.FheUint4 + input := packInputList(handle, ciphertext, unsuportedType) _, err := verifyCiphertextRun(environment, addr, addr, input, readOnly, nil) if err == nil { - t.Fatalf("verifyCiphertext must have failed on type mismatch") + t.Fatalf("verifyCiphertext must have failed on unsupported list type") } - if len(environment.FhevmData().loadedCiphertexts) != 0 { - t.Fatalf("verifyCiphertext mustn't have verified given ciphertext") + if len(environment.fhevmData.expandedInputCiphertexts) != 0 { + t.Fatalf("expected 0 expanded input ciphertexts, got %d", len(environment.fhevmData.expandedInputCiphertexts)) + } + if len(environment.fhevmData.loadedCiphertexts) != 0 { + t.Fatalf("expected 0 loaded ciphertexts, got %d", len(environment.fhevmData.loadedCiphertexts)) + } +} + +func TestVerifyCiphertextBadListType(t *testing.T) { + depth := 1 + environment := newTestEVMEnvironment() + environment.depth = depth + addr := tfheExecutorContractAddress + readOnly := false + handles, ciphertext := createInputList([]big.Int{*big.NewInt(42)}, []tfhe.FheUintType{tfhe.FheUint32}, tfhe.FheUint160) + handle := handles[0] + badType := tfhe.FheUintType(255) + input := packInputList(handle, ciphertext, badType) + _, err := verifyCiphertextRun(environment, addr, addr, input, readOnly, nil) + if err == nil { + t.Fatalf("verifyCiphertext must have failed on bad list type") + } + if len(environment.fhevmData.expandedInputCiphertexts) != 0 { + t.Fatalf("expected 0 expanded input ciphertexts, got %d", len(environment.fhevmData.expandedInputCiphertexts)) + } + if len(environment.fhevmData.loadedCiphertexts) != 0 { + t.Fatalf("expected 0 loaded ciphertexts, got %d", len(environment.fhevmData.loadedCiphertexts)) + } +} + +func TestVerifyCiphertextBadTypeInHandle(t *testing.T) { + depth := 1 + environment := newTestEVMEnvironment() + environment.depth = depth + addr := tfheExecutorContractAddress + readOnly := false + handles, ciphertext := createInputList([]big.Int{*big.NewInt(42)}, []tfhe.FheUintType{tfhe.FheUint32}, tfhe.FheUint160) + handle := handles[0] + // put a bad type in the handle + handle[30] = 255 + input := packInputList(handle, ciphertext, tfhe.FheUint160) + _, err := verifyCiphertextRun(environment, addr, addr, input, readOnly, nil) + if err == nil { + t.Fatalf("verifyCiphertext must have failed on bad type in handle") + } + if len(environment.fhevmData.expandedInputCiphertexts) != 0 { + t.Fatalf("expected 0 expanded input ciphertexts, got %d", len(environment.fhevmData.expandedInputCiphertexts)) + } + if len(environment.fhevmData.loadedCiphertexts) != 0 { + t.Fatalf("expected 0 loaded ciphertexts, got %d", len(environment.fhevmData.loadedCiphertexts)) + } +} + +func TestVerifyCiphertextBadHashInHandle(t *testing.T) { + depth := 1 + environment := newTestEVMEnvironment() + environment.depth = depth + addr := tfheExecutorContractAddress + readOnly := false + handles, ciphertext := createInputList([]big.Int{*big.NewInt(42)}, []tfhe.FheUintType{tfhe.FheUint32}, tfhe.FheUint160) + handle := handles[0] + // change hash such that it is not correct + handle[0]++ + input := packInputList(handle, ciphertext, tfhe.FheUint160) + _, err := verifyCiphertextRun(environment, addr, addr, input, readOnly, nil) + if err == nil { + t.Fatalf("verifyCiphertext must have failed on bad hash in handle") + } + if len(environment.fhevmData.expandedInputCiphertexts) != 0 { + t.Fatalf("expected 0 expanded input ciphertexts, got %d", len(environment.fhevmData.expandedInputCiphertexts)) + } + if len(environment.fhevmData.loadedCiphertexts) != 0 { + t.Fatalf("expected 0 loaded ciphertexts, got %d", len(environment.fhevmData.loadedCiphertexts)) + } +} + +func TestVerifyCiphertextIndexOutOfRangeInHandle(t *testing.T) { + depth := 1 + environment := newTestEVMEnvironment() + environment.depth = depth + addr := tfheExecutorContractAddress + readOnly := false + handles, ciphertext := createInputListWithBadIndex([]big.Int{*big.NewInt(42)}, []tfhe.FheUintType{tfhe.FheUint32}, tfhe.FheUint160) + handle := handles[0] + input := packInputList(handle, ciphertext, tfhe.FheUint160) + _, err := verifyCiphertextRun(environment, addr, addr, input, readOnly, nil) + if err == nil { + t.Fatalf("verifyCiphertext must have failed on index out of range in handle") + } + if len(environment.fhevmData.expandedInputCiphertexts) != 0 { + t.Fatalf("expected 0 expanded input ciphertexts, got %d", len(environment.fhevmData.expandedInputCiphertexts)) + } + if len(environment.fhevmData.loadedCiphertexts) != 0 { + t.Fatalf("expected 0 loaded ciphertexts, got %d", len(environment.fhevmData.loadedCiphertexts)) } } @@ -1787,31 +1961,6 @@ func LibDecrypt(t *testing.T, fheUintType tfhe.FheUintType) { } } -func TestLibVerifyCiphertextInvalidType(t *testing.T) { - signature := "verifyCiphertext(bytes)" - hashRes := crypto.Keccak256([]byte(signature)) - signatureBytes := hashRes[0:4] - depth := 1 - environment := newTestEVMEnvironment() - environment.depth = depth - addr := tfheExecutorContractAddress - readOnly := false - invalidType := tfhe.FheUintType(255) - input := make([]byte, 0) - input = append(input, signatureBytes...) - compact := tfhe.EncryptAndSerializeCompact(0, tfhe.FheUint32) - input = append(input, compact...) - input = append(input, byte(invalidType)) - _, err := FheLibRun(environment, addr, addr, input, readOnly) - if err == nil { - t.Fatalf("verifyCiphertext must have failed on invalid ciphertext type") - } - - if !strings.Contains(err.Error(), "ciphertext type is invalid") { - t.Fatalf("Unexpected test error: %s", err.Error()) - } -} - // TODO: can be enabled if mocking kms or running a kms during tests // func TestLibReencrypt(t *testing.T) { // signature := "reencrypt(uint256,uint256)" @@ -2381,6 +2530,12 @@ func FheEq(t *testing.T, fheUintType tfhe.FheUintType, scalar bool) { case tfhe.FheUint64: lhs = 13333377777 rhs = 133337 + case tfhe.FheUint160: + lhs = 133333777776 + rhs = 1333376 + case tfhe.FheUint2048: + lhs = 133333777778 + rhs = 1333378 } depth := 1 environment := newTestEVMEnvironment() @@ -3531,21 +3686,6 @@ func TestFheArrayEqUnverifiedCtInRhs(t *testing.T) { } } -func TestVerifyCiphertextInvalidType(t *testing.T) { - depth := 1 - environment := newTestEVMEnvironment() - environment.depth = depth - addr := tfheExecutorContractAddress - readOnly := false - invalidType := tfhe.FheUintType(255) - compact := tfhe.EncryptAndSerializeCompact(0, tfhe.FheUint64) - input := prepareInputForVerifyCiphertext(append(compact, byte(invalidType))) - _, err := verifyCiphertextRun(environment, addr, addr, input, readOnly, nil) - if err == nil { - t.Fatalf("verifyCiphertext must have failed on invalid ciphertext type") - } -} - func TestTrivialEncryptInvalidType(t *testing.T) { // TODO: maybe trivialEncryptRun shouldn't panic but return an error? defer func() { @@ -3581,39 +3721,36 @@ func TestCastInvalidType(t *testing.T) { } } -func TestVerifyCiphertextInvalidSize(t *testing.T) { - depth := 1 - environment := newTestEVMEnvironment() - environment.depth = depth - addr := tfheExecutorContractAddress - readOnly := false - ctType := tfhe.FheUint32 - compact := tfhe.EncryptAndSerializeCompact(0, ctType) - input := prepareInputForVerifyCiphertext(append(compact[:len(compact)-1], byte(ctType))) - _, err := verifyCiphertextRun(environment, addr, addr, input, readOnly, nil) - if err == nil { - t.Fatalf("verifyCiphertext must have failed on invalid ciphertext size") - } +func TestVerifyCiphertextList160TypeBool(t *testing.T) { + VerifyCiphertextList(t, tfhe.FheUint160, tfhe.FheBool) +} + +func TestVerifyCiphertextList160Type4(t *testing.T) { + VerifyCiphertextList(t, tfhe.FheUint160, tfhe.FheUint4) +} + +func TestVerifyCiphertextList160Type8(t *testing.T) { + VerifyCiphertextList(t, tfhe.FheUint160, tfhe.FheUint8) } -func TestVerifyCiphertext4(t *testing.T) { - VerifyCiphertext(t, tfhe.FheUint4) +func TestVerifyCiphertextList160Type16(t *testing.T) { + VerifyCiphertextList(t, tfhe.FheUint160, tfhe.FheUint16) } -func TestVerifyCiphertext8(t *testing.T) { - VerifyCiphertext(t, tfhe.FheUint8) +func TestVerifyCiphertextList160Type32(t *testing.T) { + VerifyCiphertextList(t, tfhe.FheUint160, tfhe.FheUint32) } -func TestVerifyCiphertext16(t *testing.T) { - VerifyCiphertext(t, tfhe.FheUint16) +func TestVerifyCiphertextList160Type64(t *testing.T) { + VerifyCiphertextList(t, tfhe.FheUint160, tfhe.FheUint64) } -func TestVerifyCiphertext32(t *testing.T) { - VerifyCiphertext(t, tfhe.FheUint32) +func TestVerifyCiphertextList160Type160(t *testing.T) { + VerifyCiphertextList(t, tfhe.FheUint160, tfhe.FheUint160) } -func TestVerifyCiphertext64(t *testing.T) { - VerifyCiphertext(t, tfhe.FheUint64) +func TestVerifyCiphertextList2048Type2048(t *testing.T) { + VerifyCiphertextList(t, tfhe.FheUint2048, tfhe.FheUint2048) } func TestTrivialEncrypt4(t *testing.T) { @@ -3636,57 +3773,6 @@ func TestTrivialEncrypt64(t *testing.T) { TrivialEncrypt(t, tfhe.FheUint64) } -func TestVerifyCiphertext4BadType(t *testing.T) { - VerifyCiphertextBadType(t, tfhe.FheUint4, tfhe.FheUint8) - VerifyCiphertextBadType(t, tfhe.FheUint4, tfhe.FheUint16) - VerifyCiphertextBadType(t, tfhe.FheUint4, tfhe.FheUint32) - VerifyCiphertextBadType(t, tfhe.FheUint4, tfhe.FheUint64) -} - -func TestVerifyCiphertext8BadType(t *testing.T) { - VerifyCiphertextBadType(t, tfhe.FheUint8, tfhe.FheUint4) - VerifyCiphertextBadType(t, tfhe.FheUint8, tfhe.FheUint16) - VerifyCiphertextBadType(t, tfhe.FheUint8, tfhe.FheUint32) - VerifyCiphertextBadType(t, tfhe.FheUint8, tfhe.FheUint64) -} - -func TestVerifyCiphertext16BadType(t *testing.T) { - VerifyCiphertextBadType(t, tfhe.FheUint16, tfhe.FheUint4) - VerifyCiphertextBadType(t, tfhe.FheUint16, tfhe.FheUint8) - VerifyCiphertextBadType(t, tfhe.FheUint16, tfhe.FheUint32) - VerifyCiphertextBadType(t, tfhe.FheUint16, tfhe.FheUint64) -} - -func TestVerifyCiphertext32BadType(t *testing.T) { - VerifyCiphertextBadType(t, tfhe.FheUint32, tfhe.FheUint4) - VerifyCiphertextBadType(t, tfhe.FheUint32, tfhe.FheUint8) - VerifyCiphertextBadType(t, tfhe.FheUint32, tfhe.FheUint16) - VerifyCiphertextBadType(t, tfhe.FheUint32, tfhe.FheUint64) -} - -func TestVerifyCiphertext64BadType(t *testing.T) { - VerifyCiphertextBadType(t, tfhe.FheUint64, tfhe.FheUint4) - VerifyCiphertextBadType(t, tfhe.FheUint64, tfhe.FheUint8) - VerifyCiphertextBadType(t, tfhe.FheUint64, tfhe.FheUint16) - VerifyCiphertextBadType(t, tfhe.FheUint64, tfhe.FheUint32) -} - -func TestVerifyCiphertextBadCiphertext(t *testing.T) { - depth := 1 - environment := newTestEVMEnvironment() - environment.depth = depth - addr := tfheExecutorContractAddress - readOnly := false - input := prepareInputForVerifyCiphertext(make([]byte, 10)) - _, err := verifyCiphertextRun(environment, addr, addr, input, readOnly, nil) - if err == nil { - t.Fatalf("verifyCiphertext must fail on bad ciphertext input") - } - if len(environment.FhevmData().loadedCiphertexts) != 0 { - t.Fatalf("verifyCiphertext mustn't have verified given ciphertext") - } -} - func TestFheLibBitAndBool(t *testing.T) { FheLibBitAnd(t, tfhe.FheBool, false) } @@ -4256,6 +4342,10 @@ func TestFheScalarShr64(t *testing.T) { FheShr(t, tfhe.FheUint64, true) } +func TestFheEq4(t *testing.T) { + FheEq(t, tfhe.FheUint4, false) +} + func TestFheEq8(t *testing.T) { FheEq(t, tfhe.FheUint8, false) } @@ -4272,6 +4362,18 @@ func TestFheEq64(t *testing.T) { FheEq(t, tfhe.FheUint64, false) } +func TestFheEq160(t *testing.T) { + FheEq(t, tfhe.FheUint160, false) +} + +func TestFheEq2048(t *testing.T) { + FheEq(t, tfhe.FheUint2048, false) +} + +func TestFheScalarEq4(t *testing.T) { + FheEq(t, tfhe.FheUint4, true) +} + func TestFheScalarEq8(t *testing.T) { FheEq(t, tfhe.FheUint8, true) } @@ -4288,6 +4390,14 @@ func TestFheScalarEq64(t *testing.T) { FheEq(t, tfhe.FheUint64, true) } +func TestFheScalarEq160(t *testing.T) { + FheEq(t, tfhe.FheUint160, true) +} + +func TestFheScalarEq2048(t *testing.T) { + FheEq(t, tfhe.FheUint2048, true) +} + func TestFheNe8(t *testing.T) { FheNe(t, tfhe.FheUint8, false) } @@ -4791,14 +4901,6 @@ func newInterpreterFromEnvironment(environment *MockEVMEnvironment) *vm.EVMInter return interpreter } -func newStopOpcodeContract() *vm.Contract { - addr := vm.AccountRef{} - c := vm.NewContract(addr, addr, big.NewInt(0), 100000) - c.Code = make([]byte, 1) - c.Code[0] = byte(vm.STOP) - return c -} - func TestDecryptInTransactionDisabled(t *testing.T) { depth := 0 environment := newTestEVMEnvironment() @@ -4840,7 +4942,7 @@ func TestFheLibGetCiphertextNonExistentHandle(t *testing.T) { readOnly := true value := big.NewInt(42) ct := new(tfhe.TfheCiphertext).TrivialEncrypt(*value, tfhe.FheUint32) - persistCiphertext(environment, ct) + persistCiphertext(environment, ct.GetHash(), ct) // Change the handle so that it won't exist. handle := ct.GetHash().Bytes() handle[2]++ @@ -4861,7 +4963,7 @@ func FheLibGetCiphertext(t *testing.T, fheUintType tfhe.FheUintType) { readOnly := true value := big.NewInt(1) ct := new(tfhe.TfheCiphertext).TrivialEncrypt(*value, fheUintType) - persistCiphertext(environment, ct) + persistCiphertext(environment, ct.GetHash(), ct) originalSer := ct.Serialize() input := make([]byte, 0) signature := crypto.Keccak256([]byte("getCiphertext(uint256)"))[0:4] diff --git a/fhevm/evm.go b/fhevm/evm.go index b5cd0e3..4221c24 100644 --- a/fhevm/evm.go +++ b/fhevm/evm.go @@ -60,7 +60,7 @@ func insertRandomCiphertext(environment EVMEnvironment, t tfhe.FheUintType) []by ct := new(tfhe.TfheCiphertext) ct.FheUintType = t ct.Hash = &handle - insertCiphertextToMemory(environment, ct) + insertCiphertextToMemory(environment, handle, ct) temp := nextCtHash.Clone() nextCtHash.Add(temp, uint256.NewInt(1)) return ct.GetHash().Bytes() diff --git a/fhevm/fhelib.go b/fhevm/fhelib.go index 029fc36..c31410f 100644 --- a/fhevm/fhelib.go +++ b/fhevm/fhelib.go @@ -241,7 +241,7 @@ var fhelibMethods = []*FheLibMethod{ }, { name: "verifyCiphertext", - argTypes: "(bytes)", + argTypes: "(bytes32,address,bytes,bytes1)", requiredGasFunction: verifyCiphertextRequiredGas, runFunction: verifyCiphertextRun, }, diff --git a/fhevm/instructions.go b/fhevm/instructions.go index 2296f9e..79035ca 100644 --- a/fhevm/instructions.go +++ b/fhevm/instructions.go @@ -22,7 +22,7 @@ func OpSstore(pc *uint64, env EVMEnvironment, scope ScopeContext) ([]byte, error if newValHash != oldValHash && env.IsCommitting() { ct := GetCiphertextFromMemory(env, newValHash) if ct != nil { - persistCiphertext(env, ct) + persistCiphertext(env, newValHash, ct) } } // Set the SSTORE's value in the actual contract. diff --git a/fhevm/interface.go b/fhevm/interface.go index 160332e..28eb56e 100644 --- a/fhevm/interface.go +++ b/fhevm/interface.go @@ -47,6 +47,9 @@ type FhevmData struct { // A map from a ciphertext hash to the ciphertext itself. loadedCiphertexts map[common.Hash]*tfhe.TfheCiphertext + // A map from the hash of the ciphertext list to an array of expanded ciphertexts. + expandedInputCiphertexts map[common.Hash][]*tfhe.TfheCiphertext + nextCiphertextHashOnGasEst uint256.Int } diff --git a/fhevm/operators_arithmetic.go b/fhevm/operators_arithmetic.go index d4a01df..c4b6315 100644 --- a/fhevm/operators_arithmetic.go +++ b/fhevm/operators_arithmetic.go @@ -42,9 +42,9 @@ func fheAddRun(environment EVMEnvironment, caller common.Address, addr common.Ad logger.Error("fheAdd failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheAdd success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.GetHash().Hex(), "result", resultHash.Hex()) return resultHash[:], nil @@ -66,9 +66,9 @@ func fheAddRun(environment EVMEnvironment, caller common.Address, addr common.Ad logger.Error("fheAdd failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheAdd scalar success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) return resultHash[:], nil } @@ -108,9 +108,9 @@ func fheSubRun(environment EVMEnvironment, caller common.Address, addr common.Ad logger.Error("fheSub failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheSub success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.GetHash().Hex(), "result", resultHash.Hex()) return resultHash[:], nil @@ -132,9 +132,9 @@ func fheSubRun(environment EVMEnvironment, caller common.Address, addr common.Ad logger.Error("fheSub failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheSub scalar success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) return resultHash[:], nil } @@ -174,9 +174,9 @@ func fheMulRun(environment EVMEnvironment, caller common.Address, addr common.Ad logger.Error("fheMul failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheMul success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.GetHash().Hex(), "result", resultHash.Hex()) return resultHash[:], nil @@ -198,9 +198,9 @@ func fheMulRun(environment EVMEnvironment, caller common.Address, addr common.Ad logger.Error("fheMul failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheMul scalar success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) return resultHash[:], nil } @@ -239,9 +239,9 @@ func fheDivRun(environment EVMEnvironment, caller common.Address, addr common.Ad logger.Error("fheDiv failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheDiv scalar success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) return resultHash[:], nil } @@ -280,9 +280,9 @@ func fheRemRun(environment EVMEnvironment, caller common.Address, addr common.Ad logger.Error("fheRem failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheRem scalar success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) return resultHash[:], nil } diff --git a/fhevm/operators_bit.go b/fhevm/operators_bit.go index a21cf09..8fcef67 100644 --- a/fhevm/operators_bit.go +++ b/fhevm/operators_bit.go @@ -42,9 +42,9 @@ func fheShlRun(environment EVMEnvironment, caller common.Address, addr common.Ad logger.Error("fheShl failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheShl success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.GetHash().Hex(), "result", resultHash.Hex()) return resultHash[:], nil @@ -66,9 +66,9 @@ func fheShlRun(environment EVMEnvironment, caller common.Address, addr common.Ad logger.Error("fheShl failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheShl scalar success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) return resultHash[:], nil } @@ -108,9 +108,9 @@ func fheShrRun(environment EVMEnvironment, caller common.Address, addr common.Ad logger.Error("fheShr failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheShr success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.GetHash().Hex(), "result", resultHash.Hex()) return resultHash[:], nil @@ -132,9 +132,9 @@ func fheShrRun(environment EVMEnvironment, caller common.Address, addr common.Ad logger.Error("fheShr failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheShr scalar success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) return resultHash[:], nil } @@ -174,9 +174,9 @@ func fheRotlRun(environment EVMEnvironment, caller common.Address, addr common.A logger.Error("fheRotl failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheRotl success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.GetHash().Hex(), "result", resultHash.Hex()) return resultHash[:], nil @@ -198,9 +198,9 @@ func fheRotlRun(environment EVMEnvironment, caller common.Address, addr common.A logger.Error("fheRotl failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheRotl scalar success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) return resultHash[:], nil } @@ -240,9 +240,9 @@ func fheRotrRun(environment EVMEnvironment, caller common.Address, addr common.A logger.Error("fheRotr failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheRotr success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.GetHash().Hex(), "result", resultHash.Hex()) return resultHash[:], nil @@ -264,9 +264,9 @@ func fheRotrRun(environment EVMEnvironment, caller common.Address, addr common.A logger.Error("fheRotr failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheRotr scalar success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) return resultHash[:], nil } @@ -302,9 +302,9 @@ func fheNegRun(environment EVMEnvironment, caller common.Address, addr common.Ad logger.Error("fheNeg failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheNeg success", "ct", ct.GetHash().Hex(), "result", resultHash.Hex()) return resultHash[:], nil } @@ -339,9 +339,9 @@ func fheNotRun(environment EVMEnvironment, caller common.Address, addr common.Ad logger.Error("fheNot failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheNot success", "ct", ct.GetHash().Hex(), "result", resultHash.Hex()) return resultHash[:], nil } @@ -386,9 +386,9 @@ func fheBitAndRun(environment EVMEnvironment, caller common.Address, addr common logger.Error("fheBitAnd failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheBitAnd success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.GetHash().Hex(), "result", resultHash.Hex()) return resultHash[:], nil } @@ -433,9 +433,9 @@ func fheBitOrRun(environment EVMEnvironment, caller common.Address, addr common. logger.Error("fheBitOr failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheBitOr success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.GetHash().Hex(), "result", resultHash.Hex()) return resultHash[:], nil } @@ -480,9 +480,9 @@ func fheBitXorRun(environment EVMEnvironment, caller common.Address, addr common logger.Error("fheBitXor failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheBitXor success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.GetHash().Hex(), "result", resultHash.Hex()) return resultHash[:], nil } diff --git a/fhevm/operators_comparison.go b/fhevm/operators_comparison.go index aa59edb..c1b0e6b 100644 --- a/fhevm/operators_comparison.go +++ b/fhevm/operators_comparison.go @@ -47,9 +47,9 @@ func fheLeRun(environment EVMEnvironment, caller common.Address, addr common.Add logger.Error("fheLe failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheLe success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.GetHash().Hex(), "result", resultHash.Hex()) return resultHash[:], nil @@ -71,9 +71,9 @@ func fheLeRun(environment EVMEnvironment, caller common.Address, addr common.Add logger.Error("fheLe failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheLe scalar success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) return resultHash[:], nil } @@ -113,9 +113,9 @@ func fheLtRun(environment EVMEnvironment, caller common.Address, addr common.Add logger.Error("fheLt failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheLt success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.GetHash().Hex(), "result", resultHash.Hex()) return resultHash[:], nil @@ -137,9 +137,9 @@ func fheLtRun(environment EVMEnvironment, caller common.Address, addr common.Add logger.Error("fheLt failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheLt scalar success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) return resultHash[:], nil } @@ -179,9 +179,9 @@ func fheEqRun(environment EVMEnvironment, caller common.Address, addr common.Add logger.Error("fheEq failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheEq success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.GetHash().Hex(), "result", resultHash.Hex()) return resultHash[:], nil @@ -203,9 +203,9 @@ func fheEqRun(environment EVMEnvironment, caller common.Address, addr common.Add logger.Error("fheEq failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheEq scalar success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) return resultHash[:], nil } @@ -245,9 +245,9 @@ func fheGeRun(environment EVMEnvironment, caller common.Address, addr common.Add logger.Error("fheGe failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheGe success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.GetHash().Hex(), "result", resultHash.Hex()) return resultHash[:], nil @@ -269,9 +269,9 @@ func fheGeRun(environment EVMEnvironment, caller common.Address, addr common.Add logger.Error("fheGe failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheGe scalar success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) return resultHash[:], nil } @@ -311,9 +311,9 @@ func fheGtRun(environment EVMEnvironment, caller common.Address, addr common.Add logger.Error("fheGt failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheGt success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.GetHash().Hex(), "result", resultHash.Hex()) return resultHash[:], nil @@ -335,9 +335,9 @@ func fheGtRun(environment EVMEnvironment, caller common.Address, addr common.Add logger.Error("fheGt failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheGt scalar success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) return resultHash[:], nil } @@ -377,9 +377,9 @@ func fheNeRun(environment EVMEnvironment, caller common.Address, addr common.Add logger.Error("fheNe failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheNe success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.GetHash().Hex(), "result", resultHash.Hex()) return resultHash[:], nil @@ -401,9 +401,9 @@ func fheNeRun(environment EVMEnvironment, caller common.Address, addr common.Add logger.Error("fheNe failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheNe scalar success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) return resultHash[:], nil } @@ -443,9 +443,9 @@ func fheMinRun(environment EVMEnvironment, caller common.Address, addr common.Ad logger.Error("fheMin failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheMin success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.GetHash().Hex(), "result", resultHash.Hex()) return resultHash[:], nil @@ -467,9 +467,9 @@ func fheMinRun(environment EVMEnvironment, caller common.Address, addr common.Ad logger.Error("fheMin failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheMin scalar success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) return resultHash[:], nil } @@ -509,9 +509,9 @@ func fheMaxRun(environment EVMEnvironment, caller common.Address, addr common.Ad logger.Error("fheMax failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheMax success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.GetHash().Hex(), "result", resultHash.Hex()) return resultHash[:], nil @@ -533,9 +533,9 @@ func fheMaxRun(environment EVMEnvironment, caller common.Address, addr common.Ad logger.Error("fheMax failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheMax scalar success", "lhs", lhs.GetHash().Hex(), "rhs", rhs.Uint64(), "result", resultHash.Hex()) return resultHash[:], nil } @@ -568,9 +568,9 @@ func fheIfThenElseRun(environment EVMEnvironment, caller common.Address, addr co logger.Error("fheIfThenElse failed", "err", err) return nil, err } - insertCiphertextToMemory(environment, result) - resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) + logger.Info("fheIfThenElse success", "first", first.GetHash().Hex(), "second", second.GetHash().Hex(), "third", third.GetHash().Hex(), "result", resultHash.Hex()) return resultHash[:], nil } @@ -676,8 +676,8 @@ func fheArrayEqRun(environment EVMEnvironment, caller common.Address, addr commo logger.Error(msg, "err", err) return nil, err } - insertCiphertextToMemory(environment, result) resultHash := result.GetHash() + insertCiphertextToMemory(environment, resultHash, result) logger.Info("fheArrayEqRun success", "result", resultHash.Hex()) return resultHash[:], nil } diff --git a/fhevm/operators_crypto.go b/fhevm/operators_crypto.go index f22e8a1..55b56bf 100644 --- a/fhevm/operators_crypto.go +++ b/fhevm/operators_crypto.go @@ -3,14 +3,16 @@ package fhevm import ( "bytes" "context" - "encoding/binary" "encoding/hex" "errors" "fmt" "math/big" + "strings" "time" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "github.com/zama-ai/fhevm-go/fhevm/kms" "github.com/zama-ai/fhevm-go/fhevm/tfhe" "go.opentelemetry.io/otel/trace" @@ -18,69 +20,163 @@ import ( "google.golang.org/grpc/credentials/insecure" ) -func verifyCiphertextRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool, runSpan trace.Span) ([]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 +const verifyCipertextAbiJson = ` + [ + { + "name": "verifyCiphertext", + "type": "function", + "inputs": [ + { + "name": "inputHandle", + "type": "bytes32" + }, + { + "name": "callerAddress", + "type": "address" + }, + { + "name": "inputProof", + "type": "bytes" + }, + { + "name": "inputType", + "type": "bytes1" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ] + } + ] +` + +var verifyCipertextMethod abi.Method + +func init() { + reader := strings.NewReader(verifyCipertextAbiJson) + verifyCiphertextAbi, err := abi.JSON(reader) + if err != nil { + panic(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) + + var ok bool + verifyCipertextMethod, ok = verifyCiphertextAbi.Methods["verifyCiphertext"] + if !ok { + panic("couldn't find the verifyCiphertext method") } +} - ctBytes := input[:len(input)-1] - ctTypeByte := input[len(input)-1] - if !tfhe.IsValidFheType(ctTypeByte) { - msg := "verifyCiphertext Run() ciphertext type is invalid" - logger.Error(msg, "type", ctTypeByte) - return nil, errors.New(msg) +func parseVerifyCiphertextInput(environment EVMEnvironment, input []byte) ([32]byte, *tfhe.TfheCiphertext, error) { + unpacked, err := verifyCipertextMethod.Inputs.UnpackValues(input) + if err != nil { + return [32]byte{}, nil, err + } else if len(unpacked) != 4 { + return [32]byte{}, nil, fmt.Errorf("parseVerifyCiphertextInput unexpected unpacked len: %d", len(unpacked)) } - ctType := tfhe.FheUintType(ctTypeByte) - otelDescribeOperandsFheTypes(runSpan, ctType) - expectedSize, found := tfhe.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) + // Get handle from input. + handle, ok := unpacked[0].([32]byte) + if !ok { + return [32]byte{}, nil, fmt.Errorf("parseVerifyCiphertextInput failed to parse bytes32 inputHandle") } - // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. - if !environment.IsCommitting() && !environment.IsEthCall() { - return insertRandomCiphertext(environment, ctType), nil + // Get the ciphertext from the input. + ciphertextList, ok := unpacked[2].([]byte) + if !ok || len(ciphertextList) == 0 { + return [32]byte{}, nil, fmt.Errorf("parseVerifyCiphertextInput failed to parse bytes inputProof") + } + + // Get the type from the input list. + inputTypeByteArray, ok := unpacked[3].([1]byte) + if !ok { + return [32]byte{}, nil, fmt.Errorf("parseVerifyCiphertextInput failed to parse byte inputType") + } + if !tfhe.IsValidFheType(inputTypeByteArray[0]) { + return [32]byte{}, nil, fmt.Errorf("parseVerifyCiphertextInput invalid inputType") + } + inputType := tfhe.FheUintType(inputTypeByteArray[0]) + if inputType != tfhe.FheUint160 && inputType != tfhe.FheUint2048 { + return [32]byte{}, nil, fmt.Errorf("parseVerifyCiphertextInput unsupported inputType") + } + + // Get the type from the handle. + handleIndex := uint8(handle[29]) + handleTypeByte := handle[30] + if !tfhe.IsValidFheType(handleTypeByte) { + return [32]byte{}, nil, fmt.Errorf("parseVerifyCiphertextInput invalid handleType") + } + handleType := tfhe.FheUintType(handleTypeByte) + + // Make sure hash in the handle is correct. + ciphertextListAndIndexHash := crypto.Keccak256Hash(append(ciphertextList, handleIndex)) + ciphertextListHash := crypto.Keccak256Hash(ciphertextList) + if !bytes.Equal(ciphertextListAndIndexHash[:29], handle[:29]) { + return [32]byte{}, nil, fmt.Errorf("parseVerifyCiphertextInput input hash doesn't match handle hash") + } + + var cts []*tfhe.TfheCiphertext + if environment.FhevmData().expandedInputCiphertexts == nil { + environment.FhevmData().expandedInputCiphertexts = make(map[common.Hash][]*tfhe.TfheCiphertext) } + if cts, ok = environment.FhevmData().expandedInputCiphertexts[ciphertextListHash]; !ok { + if inputType == tfhe.FheUint160 { + cts, err = tfhe.DeserializeAndExpandCompact160List(ciphertextList) + } else { + cts, err = tfhe.DeserializeAndExpandCompact2048List(ciphertextList) + } + + if err != nil { + return [32]byte{}, nil, err + } + } + + // Extract ciphertext from the list via the handle index. + if int(handleIndex) >= len(cts) { + return [32]byte{}, nil, fmt.Errorf("parseVerifyCiphertextInput ciphertext index out of range") + } + ct := cts[handleIndex] + + // Cast, if needed. + if inputType == tfhe.FheUint2048 { + if handleType != tfhe.FheUint2048 { + return [32]byte{}, nil, fmt.Errorf("parseVerifyCiphertextInput only FheUint2048 allowed in FheUint2048List") + } + } else { + if handleType != ct.Type() { + ct, err = ct.CastTo(handleType) + if err != nil { + return [32]byte{}, nil, err + } + } + } + environment.FhevmData().expandedInputCiphertexts[ciphertextListHash] = cts + return handle, ct, nil +} - ct := new(tfhe.TfheCiphertext) - err := ct.DeserializeCompact(ctBytes, ctType) +func verifyCiphertextRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool, runSpan trace.Span) ([]byte, error) { + logger := environment.GetLogger() + + handle, ct, err := parseVerifyCiphertextInput(environment, input) if err != nil { - logger.Error("verifyCiphertext failed to deserialize input ciphertext", - "err", err, - "len", len(ctBytes), - "ctBytes64", hex.EncodeToString(ctBytes[:minInt(len(ctBytes), 64)])) + logger.Error(err.Error()) return nil, err } - ctHash := ct.GetHash() - insertCiphertextToMemory(environment, ct) + otelDescribeOperandsFheTypes(runSpan, ct.Type()) + + // If we are doing gas estimation, skip execution and insert a random ciphertext as a result. + if !environment.IsCommitting() && !environment.IsEthCall() { + return insertRandomCiphertext(environment, ct.Type()), nil + } + + insertCiphertextToMemory(environment, handle, ct) if environment.IsCommitting() { logger.Info("verifyCiphertext success", - "ctHash", ctHash.Hex(), - "ctBytes64", hex.EncodeToString(ctBytes[:minInt(len(ctBytes), 64)])) + "ctHash", ct.GetHash().Hex()) } - return ctHash.Bytes(), nil + return handle[:], nil } func reencryptRun(environment EVMEnvironment, caller common.Address, addr common.Address, input []byte, readOnly bool, runSpan trace.Span) ([]byte, error) { @@ -337,7 +433,7 @@ func castRun(environment EVMEnvironment, caller common.Address, addr common.Addr resHash := res.GetHash() - insertCiphertextToMemory(environment, res) + insertCiphertextToMemory(environment, resHash, res) if environment.IsCommitting() { logger.Info("cast success", "ctHash", resHash.Hex(), @@ -392,7 +488,7 @@ func trivialEncryptRun(environment EVMEnvironment, caller common.Address, addr c ct := new(tfhe.TfheCiphertext).TrivialEncrypt(valueToEncrypt, encryptToType) ctHash := ct.GetHash() - insertCiphertextToMemory(environment, ct) + insertCiphertextToMemory(environment, ctHash, ct) if environment.IsCommitting() { logger.Info("trivialEncrypt success", "ctHash", ctHash.Hex(), diff --git a/fhevm/operators_crypto_gas.go b/fhevm/operators_crypto_gas.go index ec45e63..3a73700 100644 --- a/fhevm/operators_crypto_gas.go +++ b/fhevm/operators_crypto_gas.go @@ -8,14 +8,14 @@ import ( ) func verifyCiphertextRequiredGas(environment EVMEnvironment, input []byte) uint64 { - if len(input) <= 1 { + _, ct, err := parseVerifyCiphertextInput(environment, input) + if err != nil { environment.GetLogger().Error( - "verifyCiphertext RequiredGas() input needs to contain a ciphertext and one byte for its type", - "len", len(input)) + "verifyCiphertext RequiredGas() input parsing failed", + "err", err) return 0 } - ctType := tfhe.FheUintType(input[len(input)-1]) - return environment.FhevmParams().GasCosts.FheVerify[ctType] + return environment.FhevmParams().GasCosts.FheVerify[ct.Type()] } func reencryptRequiredGas(environment EVMEnvironment, input []byte) uint64 { diff --git a/fhevm/operators_rand.go b/fhevm/operators_rand.go index 1a22ce9..2e9fad9 100644 --- a/fhevm/operators_rand.go +++ b/fhevm/operators_rand.go @@ -131,12 +131,8 @@ func generateRandom(environment EVMEnvironment, caller common.Address, resultTyp randBigInt := big.NewInt(0) randBigInt.SetUint64(randUint) randCt.TrivialEncrypt(*randBigInt, resultType) - insertCiphertextToMemory(environment, randCt) - - if err != nil { - return nil, err - } ctHash := randCt.GetHash() + insertCiphertextToMemory(environment, ctHash, randCt) return ctHash[:], nil } diff --git a/fhevm/tfhe/tfhe_ciphertext.go b/fhevm/tfhe/tfhe_ciphertext.go index 529f7a2..f7e1eee 100644 --- a/fhevm/tfhe/tfhe_ciphertext.go +++ b/fhevm/tfhe/tfhe_ciphertext.go @@ -18,16 +18,20 @@ import ( type FheUintType uint8 const ( - FheBool FheUintType = 0 - FheUint4 FheUintType = 1 - FheUint8 FheUintType = 2 - FheUint16 FheUintType = 3 - FheUint32 FheUintType = 4 - FheUint64 FheUintType = 5 - FheUint128 FheUintType = 6 - FheUint160 FheUintType = 7 + FheBool FheUintType = 0 + FheUint4 FheUintType = 1 + FheUint8 FheUintType = 2 + FheUint16 FheUintType = 3 + FheUint32 FheUintType = 4 + FheUint64 FheUintType = 5 + FheUint128 FheUintType = 6 + FheUint160 FheUintType = 7 + FheUint2048 FheUintType = 11 ) +// The version to use when computing ciphertext hashes. +const HashVersion = 0 + func (t FheUintType) String() string { switch t { case FheBool: @@ -46,6 +50,8 @@ func (t FheUintType) String() string { return "fheUint128" case FheUint160: return "fheUint160" + case FheUint2048: + return "fheUint2048" default: return "unknown FheUintType" } @@ -69,13 +75,16 @@ func (t FheUintType) NumBits() uint { return 128 case FheUint160: return 160 + case FheUint2048: + return 2048 default: panic("unknown FheUintType") } } func IsValidFheType(t byte) bool { - if uint8(t) < uint8(FheBool) || uint8(t) > uint8(FheUint160) { + u := uint8(t) + if u < uint8(FheBool) || (u > uint8(FheUint160) && u != uint8(FheUint2048)) { return false } return true @@ -92,23 +101,31 @@ func (ct *TfheCiphertext) Type() FheUintType { return ct.FheUintType } func boolBinaryNotSupportedOp(lhs unsafe.Pointer, rhs unsafe.Pointer) (unsafe.Pointer, error) { - return nil, errors.New("Bool is not supported") + return nil, errors.New("bool is not supported") } func boolBinaryScalarNotSupportedOp(lhs unsafe.Pointer, rhs C.bool) (unsafe.Pointer, error) { - return nil, errors.New("Bool is not supported") + return nil, errors.New("bool is not supported") } func fheUint160BinaryNotSupportedOp(lhs unsafe.Pointer, rhs unsafe.Pointer) (unsafe.Pointer, error) { - return nil, errors.New("FHEUint160 is not supported") + return nil, errors.New("fheUint160 is not supported") +} + +func fheUint2048BinaryNotSupportedOp(lhs unsafe.Pointer, rhs unsafe.Pointer) (unsafe.Pointer, error) { + return nil, errors.New("fheUint2048 is not supported") } func fheUint160BinaryScalarNotSupportedOp(lhs unsafe.Pointer, rhs C.U256) (unsafe.Pointer, error) { - return nil, errors.New("FHEUint160 is not supported") + return nil, errors.New("fheUint160 is not supported") +} + +func fheUint2048BinarScalaryNotSupportedOp(lhs unsafe.Pointer, rhs C.U2048) (unsafe.Pointer, error) { + return nil, errors.New("fheUint2048 is not supported") } func boolUnaryNotSupportedOp(lhs unsafe.Pointer) (unsafe.Pointer, error) { - return nil, errors.New("Bool is not supported") + return nil, errors.New("bool is not supported") } // Deserializes `in` and returns a C pointer to the ciphertext. @@ -129,6 +146,8 @@ func Deserialize(in []byte, t FheUintType) unsafe.Pointer { return C.deserialize_fhe_uint64(toDynamicBufferView(in)) case FheUint160: return C.deserialize_fhe_uint160(toDynamicBufferView(in)) + case FheUint2048: + return C.deserialize_fhe_uint2048(toDynamicBufferView(in)) default: panic("Deserialize: unexpected ciphertext type") } @@ -151,6 +170,8 @@ func destroyCiphertext(ptr unsafe.Pointer, t FheUintType) { C.destroy_fhe_uint64(ptr) case FheUint160: C.destroy_fhe_uint160(ptr) + case FheUint2048: + C.destroy_fhe_uint2048(ptr) default: panic("destroyCiphertext: unexpected ciphertext type") } @@ -256,6 +277,17 @@ func (ct *TfheCiphertext) DeserializeCompact(in []byte, t FheUintType) error { if err != nil { return err } + case FheUint2048: + ptr := C.deserialize_compact_fhe_uint2048(toDynamicBufferView((in))) + if ptr == nil { + return errors.New("compact FheUint2048 ciphertext deserialization failed") + } + var err error + ct.Serialization, err = serialize(ptr, t) + C.destroy_fhe_uint2048(ptr) + if err != nil { + return err + } default: panic("deserializeCompact: unexpected ciphertext type") } @@ -327,6 +359,17 @@ func (ct *TfheCiphertext) Encrypt(value big.Int, t FheUintType) *TfheCiphertext if err != nil { panic(err) } + case FheUint2048: + input, err := bigIntToU2048(&value) + if err != nil { + panic(err) + } + ptr = C.public_key_encrypt_fhe_uint2048(pks, input) + ct.Serialization, err = serialize(ptr, t) + C.destroy_fhe_uint2048(ptr) + if err != nil { + panic(err) + } default: panic("encrypt: unexpected ciphertext type") } @@ -390,12 +433,23 @@ func (ct *TfheCiphertext) TrivialEncrypt(value big.Int, t FheUintType) *TfheCiph if err != nil { panic(err) } - ptr = C.trivial_encrypt_fhe_uint160(sks, *input) + ptr = C.trivial_encrypt_fhe_uint160(sks, input) ct.Serialization, err = serialize(ptr, t) C.destroy_fhe_uint160(ptr) if err != nil { panic(err) } + case FheUint2048: + input, err := bigIntToU2048(&value) + if err != nil { + panic(err) + } + ptr = C.trivial_encrypt_fhe_uint2048(sks, input) + ct.Serialization, err = serialize(ptr, t) + C.destroy_fhe_uint2048(ptr) + if err != nil { + panic(err) + } default: panic("trivialEncrypt: unexpected ciphertext type") } @@ -555,6 +609,7 @@ func (lhs *TfheCiphertext) executeBinaryCiphertextOperation(rhs *TfheCiphertext, op32 func(lhs unsafe.Pointer, rhs unsafe.Pointer) (unsafe.Pointer, error), op64 func(lhs unsafe.Pointer, rhs unsafe.Pointer) (unsafe.Pointer, error), op160 func(lhs unsafe.Pointer, rhs unsafe.Pointer) (unsafe.Pointer, error), + op2048 func(lhs unsafe.Pointer, rhs unsafe.Pointer) (unsafe.Pointer, error), returnBool bool) (*TfheCiphertext, error) { if lhs.FheUintType != rhs.FheUintType { return nil, errors.New("binary operations are only well-defined for identical types") @@ -799,6 +854,40 @@ func (lhs *TfheCiphertext) executeBinaryCiphertextOperation(rhs *TfheCiphertext, } res.Serialization = C.GoBytes(unsafe.Pointer(res_ser.pointer), C.int(res_ser.length)) C.destroy_dynamic_buffer(res_ser) + case FheUint2048: + lhs_ptr := C.deserialize_fhe_uint2048(toDynamicBufferView((lhs.Serialization))) + if lhs_ptr == nil { + return nil, errors.New("2048 bit binary op deserialization failed") + } + rhs_ptr := C.deserialize_fhe_uint2048(toDynamicBufferView((rhs.Serialization))) + if rhs_ptr == nil { + C.destroy_fhe_uint2048(lhs_ptr) + return nil, errors.New("2048 bit binary op deserialization failed") + } + res_ptr, err := op2048(lhs_ptr, rhs_ptr) + if err != nil { + return nil, err + } + C.destroy_fhe_uint2048(lhs_ptr) + C.destroy_fhe_uint2048(rhs_ptr) + if res_ptr == nil { + return nil, errors.New("2048 bit binary op failed") + } + if returnBool { + ret := C.serialize_fhe_bool(res_ptr, res_ser) + C.destroy_fhe_bool(res_ptr) + if ret != 0 { + return nil, errors.New("bool binary op serialization failed") + } + } else { + ret := C.serialize_fhe_uint2048(res_ptr, res_ser) + C.destroy_fhe_uint2048(res_ptr) + if ret != 0 { + return nil, errors.New("2048 bit binary op serialization failed") + } + } + res.Serialization = C.GoBytes(unsafe.Pointer(res_ser.pointer), C.int(res_ser.length)) + C.destroy_dynamic_buffer(res_ser) default: panic("binary op unexpected ciphertext type") } @@ -1011,6 +1100,7 @@ func (lhs *TfheCiphertext) executeBinaryScalarOperation(rhs *big.Int, op32 func(lhs unsafe.Pointer, rhs C.uint32_t) (unsafe.Pointer, error), op64 func(lhs unsafe.Pointer, rhs C.uint64_t) (unsafe.Pointer, error), op160 func(lhs unsafe.Pointer, rhs C.U256) (unsafe.Pointer, error), + op2048 func(lhs unsafe.Pointer, rhs C.U2048) (unsafe.Pointer, error), returnBool bool) (*TfheCiphertext, error) { res := new(TfheCiphertext) if returnBool { @@ -1218,6 +1308,37 @@ func (lhs *TfheCiphertext) executeBinaryScalarOperation(rhs *big.Int, } res.Serialization = C.GoBytes(unsafe.Pointer(res_ser.pointer), C.int(res_ser.length)) C.destroy_dynamic_buffer(res_ser) + case FheUint2048: + lhs_ptr := C.deserialize_fhe_uint2048(toDynamicBufferView((lhs.Serialization))) + if lhs_ptr == nil { + return nil, errors.New("2048 bit scalar op deserialization failed") + } + + scalar, err := bigIntToU2048(rhs) + + res_ptr, err := op2048(lhs_ptr, *scalar) + if err != nil { + return nil, err + } + C.destroy_fhe_uint2048(lhs_ptr) + if res_ptr == nil { + return nil, errors.New("2048 bit scalar op failed") + } + if returnBool { + ret := C.serialize_fhe_bool(res_ptr, res_ser) + C.destroy_fhe_bool(res_ptr) + if ret != 0 { + return nil, errors.New("bool scalar op serialization failed") + } + } else { + ret := C.serialize_fhe_uint2048(res_ptr, res_ser) + C.destroy_fhe_uint2048(res_ptr) + if ret != 0 { + return nil, errors.New("160 bit scalar op serialization failed") + } + } + res.Serialization = C.GoBytes(unsafe.Pointer(res_ser.pointer), C.int(res_ser.length)) + C.destroy_dynamic_buffer(res_ser) default: panic("scalar op unexpected ciphertext type") @@ -1244,7 +1365,7 @@ func (lhs *TfheCiphertext) Add(rhs *TfheCiphertext) (*TfheCiphertext, error) { func(lhs unsafe.Pointer, rhs unsafe.Pointer) (unsafe.Pointer, error) { return C.add_fhe_uint64(lhs, rhs, sks), nil }, - fheUint160BinaryNotSupportedOp, false) + fheUint160BinaryNotSupportedOp, fheUint2048BinaryNotSupportedOp, false) } func (lhs *TfheCiphertext) ScalarAdd(rhs *big.Int) (*TfheCiphertext, error) { @@ -1265,7 +1386,7 @@ func (lhs *TfheCiphertext) ScalarAdd(rhs *big.Int) (*TfheCiphertext, error) { func(lhs unsafe.Pointer, rhs C.uint64_t) (unsafe.Pointer, error) { return C.scalar_add_fhe_uint64(lhs, rhs, sks), nil }, - fheUint160BinaryScalarNotSupportedOp, false) + fheUint160BinaryScalarNotSupportedOp, fheUint2048BinarScalaryNotSupportedOp, false) } func (lhs *TfheCiphertext) Sub(rhs *TfheCiphertext) (*TfheCiphertext, error) { @@ -1286,7 +1407,7 @@ func (lhs *TfheCiphertext) Sub(rhs *TfheCiphertext) (*TfheCiphertext, error) { func(lhs unsafe.Pointer, rhs unsafe.Pointer) (unsafe.Pointer, error) { return C.sub_fhe_uint64(lhs, rhs, sks), nil }, - fheUint160BinaryNotSupportedOp, false) + fheUint160BinaryNotSupportedOp, fheUint2048BinaryNotSupportedOp, false) } func (lhs *TfheCiphertext) ScalarSub(rhs *big.Int) (*TfheCiphertext, error) { @@ -1307,7 +1428,7 @@ func (lhs *TfheCiphertext) ScalarSub(rhs *big.Int) (*TfheCiphertext, error) { func(lhs unsafe.Pointer, rhs C.uint64_t) (unsafe.Pointer, error) { return C.scalar_sub_fhe_uint64(lhs, rhs, sks), nil }, - fheUint160BinaryScalarNotSupportedOp, false) + fheUint160BinaryScalarNotSupportedOp, fheUint2048BinarScalaryNotSupportedOp, false) } func (lhs *TfheCiphertext) Mul(rhs *TfheCiphertext) (*TfheCiphertext, error) { @@ -1328,7 +1449,7 @@ func (lhs *TfheCiphertext) Mul(rhs *TfheCiphertext) (*TfheCiphertext, error) { func(lhs unsafe.Pointer, rhs unsafe.Pointer) (unsafe.Pointer, error) { return C.mul_fhe_uint64(lhs, rhs, sks), nil }, - fheUint160BinaryNotSupportedOp, false) + fheUint160BinaryNotSupportedOp, fheUint2048BinaryNotSupportedOp, false) } func (lhs *TfheCiphertext) ScalarMul(rhs *big.Int) (*TfheCiphertext, error) { @@ -1349,7 +1470,7 @@ func (lhs *TfheCiphertext) ScalarMul(rhs *big.Int) (*TfheCiphertext, error) { func(lhs unsafe.Pointer, rhs C.uint64_t) (unsafe.Pointer, error) { return C.scalar_mul_fhe_uint64(lhs, rhs, sks), nil }, - fheUint160BinaryScalarNotSupportedOp, false) + fheUint160BinaryScalarNotSupportedOp, fheUint2048BinarScalaryNotSupportedOp, false) } func (lhs *TfheCiphertext) ScalarDiv(rhs *big.Int) (*TfheCiphertext, error) { @@ -1370,7 +1491,7 @@ func (lhs *TfheCiphertext) ScalarDiv(rhs *big.Int) (*TfheCiphertext, error) { func(lhs unsafe.Pointer, rhs C.uint64_t) (unsafe.Pointer, error) { return C.scalar_div_fhe_uint64(lhs, rhs, sks), nil }, - fheUint160BinaryScalarNotSupportedOp, false) + fheUint160BinaryScalarNotSupportedOp, fheUint2048BinarScalaryNotSupportedOp, false) } func (lhs *TfheCiphertext) ScalarRem(rhs *big.Int) (*TfheCiphertext, error) { @@ -1391,7 +1512,7 @@ func (lhs *TfheCiphertext) ScalarRem(rhs *big.Int) (*TfheCiphertext, error) { func(lhs unsafe.Pointer, rhs C.uint64_t) (unsafe.Pointer, error) { return C.scalar_rem_fhe_uint64(lhs, rhs, sks), nil }, - fheUint160BinaryScalarNotSupportedOp, false) + fheUint160BinaryScalarNotSupportedOp, fheUint2048BinarScalaryNotSupportedOp, false) } func (lhs *TfheCiphertext) Bitand(rhs *TfheCiphertext) (*TfheCiphertext, error) { @@ -1414,7 +1535,7 @@ func (lhs *TfheCiphertext) Bitand(rhs *TfheCiphertext) (*TfheCiphertext, error) func(lhs unsafe.Pointer, rhs unsafe.Pointer) (unsafe.Pointer, error) { return C.bitand_fhe_uint64(lhs, rhs, sks), nil }, - fheUint160BinaryNotSupportedOp, false) + fheUint160BinaryNotSupportedOp, fheUint2048BinaryNotSupportedOp, false) } func (lhs *TfheCiphertext) Bitor(rhs *TfheCiphertext) (*TfheCiphertext, error) { @@ -1437,7 +1558,7 @@ func (lhs *TfheCiphertext) Bitor(rhs *TfheCiphertext) (*TfheCiphertext, error) { func(lhs unsafe.Pointer, rhs unsafe.Pointer) (unsafe.Pointer, error) { return C.bitor_fhe_uint64(lhs, rhs, sks), nil }, - fheUint160BinaryNotSupportedOp, false) + fheUint160BinaryNotSupportedOp, fheUint2048BinaryNotSupportedOp, false) } func (lhs *TfheCiphertext) Bitxor(rhs *TfheCiphertext) (*TfheCiphertext, error) { @@ -1460,7 +1581,7 @@ func (lhs *TfheCiphertext) Bitxor(rhs *TfheCiphertext) (*TfheCiphertext, error) func(lhs unsafe.Pointer, rhs unsafe.Pointer) (unsafe.Pointer, error) { return C.bitxor_fhe_uint64(lhs, rhs, sks), nil }, - fheUint160BinaryNotSupportedOp, false) + fheUint160BinaryNotSupportedOp, fheUint2048BinaryNotSupportedOp, false) } func (lhs *TfheCiphertext) Shl(rhs *TfheCiphertext) (*TfheCiphertext, error) { @@ -1481,7 +1602,7 @@ func (lhs *TfheCiphertext) Shl(rhs *TfheCiphertext) (*TfheCiphertext, error) { func(lhs unsafe.Pointer, rhs unsafe.Pointer) (unsafe.Pointer, error) { return C.shl_fhe_uint64(lhs, rhs, sks), nil }, - fheUint160BinaryNotSupportedOp, false) + fheUint160BinaryNotSupportedOp, fheUint2048BinaryNotSupportedOp, false) } func (lhs *TfheCiphertext) ScalarShl(rhs *big.Int) (*TfheCiphertext, error) { @@ -1502,7 +1623,7 @@ func (lhs *TfheCiphertext) ScalarShl(rhs *big.Int) (*TfheCiphertext, error) { func(lhs unsafe.Pointer, rhs C.uint64_t) (unsafe.Pointer, error) { return C.scalar_shl_fhe_uint64(lhs, rhs, sks), nil }, - fheUint160BinaryScalarNotSupportedOp, false) + fheUint160BinaryScalarNotSupportedOp, fheUint2048BinarScalaryNotSupportedOp, false) } func (lhs *TfheCiphertext) Shr(rhs *TfheCiphertext) (*TfheCiphertext, error) { @@ -1524,6 +1645,7 @@ func (lhs *TfheCiphertext) Shr(rhs *TfheCiphertext) (*TfheCiphertext, error) { return C.shr_fhe_uint64(lhs, rhs, sks), nil }, fheUint160BinaryNotSupportedOp, + fheUint2048BinaryNotSupportedOp, false) } @@ -1545,7 +1667,7 @@ func (lhs *TfheCiphertext) ScalarShr(rhs *big.Int) (*TfheCiphertext, error) { func(lhs unsafe.Pointer, rhs C.uint64_t) (unsafe.Pointer, error) { return C.scalar_shr_fhe_uint64(lhs, rhs, sks), nil }, - fheUint160BinaryScalarNotSupportedOp, false) + fheUint160BinaryScalarNotSupportedOp, fheUint2048BinarScalaryNotSupportedOp, false) } func (lhs *TfheCiphertext) Rotl(rhs *TfheCiphertext) (*TfheCiphertext, error) { @@ -1566,7 +1688,7 @@ func (lhs *TfheCiphertext) Rotl(rhs *TfheCiphertext) (*TfheCiphertext, error) { func(lhs unsafe.Pointer, rhs unsafe.Pointer) (unsafe.Pointer, error) { return C.rotl_fhe_uint64(lhs, rhs, sks), nil }, - fheUint160BinaryNotSupportedOp, false) + fheUint160BinaryNotSupportedOp, fheUint2048BinaryNotSupportedOp, false) } func (lhs *TfheCiphertext) ScalarRotl(rhs *big.Int) (*TfheCiphertext, error) { @@ -1587,7 +1709,7 @@ func (lhs *TfheCiphertext) ScalarRotl(rhs *big.Int) (*TfheCiphertext, error) { func(lhs unsafe.Pointer, rhs C.uint64_t) (unsafe.Pointer, error) { return C.scalar_rotl_fhe_uint64(lhs, rhs, sks), nil }, - fheUint160BinaryScalarNotSupportedOp, false) + fheUint160BinaryScalarNotSupportedOp, fheUint2048BinarScalaryNotSupportedOp, false) } func (lhs *TfheCiphertext) Rotr(rhs *TfheCiphertext) (*TfheCiphertext, error) { @@ -1609,6 +1731,7 @@ func (lhs *TfheCiphertext) Rotr(rhs *TfheCiphertext) (*TfheCiphertext, error) { return C.rotr_fhe_uint64(lhs, rhs, sks), nil }, fheUint160BinaryNotSupportedOp, + fheUint2048BinaryNotSupportedOp, false) } @@ -1630,7 +1753,7 @@ func (lhs *TfheCiphertext) ScalarRotr(rhs *big.Int) (*TfheCiphertext, error) { func(lhs unsafe.Pointer, rhs C.uint64_t) (unsafe.Pointer, error) { return C.scalar_rotr_fhe_uint64(lhs, rhs, sks), nil }, - fheUint160BinaryScalarNotSupportedOp, false) + fheUint160BinaryScalarNotSupportedOp, fheUint2048BinarScalaryNotSupportedOp, false) } func (lhs *TfheCiphertext) Eq(rhs *TfheCiphertext) (*TfheCiphertext, error) { @@ -1654,6 +1777,9 @@ func (lhs *TfheCiphertext) Eq(rhs *TfheCiphertext) (*TfheCiphertext, error) { func(lhs unsafe.Pointer, rhs unsafe.Pointer) (unsafe.Pointer, error) { return C.eq_fhe_uint160(lhs, rhs, sks), nil }, + func(lhs unsafe.Pointer, rhs unsafe.Pointer) (unsafe.Pointer, error) { + return C.eq_fhe_uint2048(lhs, rhs, sks), nil + }, true) } @@ -1678,6 +1804,9 @@ func (lhs *TfheCiphertext) ScalarEq(rhs *big.Int) (*TfheCiphertext, error) { func(lhs unsafe.Pointer, rhs C.U256) (unsafe.Pointer, error) { return C.scalar_eq_fhe_uint160(lhs, rhs, sks), nil }, + func(lhs unsafe.Pointer, rhs C.U2048) (unsafe.Pointer, error) { + return C.scalar_eq_fhe_uint2048(lhs, rhs, sks), nil + }, true) } @@ -1702,6 +1831,9 @@ func (lhs *TfheCiphertext) Ne(rhs *TfheCiphertext) (*TfheCiphertext, error) { func(lhs unsafe.Pointer, rhs unsafe.Pointer) (unsafe.Pointer, error) { return C.ne_fhe_uint160(lhs, rhs, sks), nil }, + func(lhs unsafe.Pointer, rhs unsafe.Pointer) (unsafe.Pointer, error) { + return C.ne_fhe_uint2048(lhs, rhs, sks), nil + }, true) } @@ -1726,6 +1858,9 @@ func (lhs *TfheCiphertext) ScalarNe(rhs *big.Int) (*TfheCiphertext, error) { func(lhs unsafe.Pointer, rhs C.U256) (unsafe.Pointer, error) { return C.scalar_ne_fhe_uint160(lhs, rhs, sks), nil }, + func(lhs unsafe.Pointer, rhs C.U2048) (unsafe.Pointer, error) { + return C.scalar_eq_fhe_uint2048(lhs, rhs, sks), nil + }, true) } @@ -1748,6 +1883,7 @@ func (lhs *TfheCiphertext) Ge(rhs *TfheCiphertext) (*TfheCiphertext, error) { return C.ge_fhe_uint64(lhs, rhs, sks), nil }, fheUint160BinaryNotSupportedOp, + fheUint2048BinaryNotSupportedOp, true) } @@ -1768,7 +1904,7 @@ func (lhs *TfheCiphertext) ScalarGe(rhs *big.Int) (*TfheCiphertext, error) { }, func(lhs unsafe.Pointer, rhs C.uint64_t) (unsafe.Pointer, error) { return C.scalar_ge_fhe_uint64(lhs, rhs, sks), nil - }, fheUint160BinaryScalarNotSupportedOp, + }, fheUint160BinaryScalarNotSupportedOp, fheUint2048BinarScalaryNotSupportedOp, true) } @@ -1791,6 +1927,7 @@ func (lhs *TfheCiphertext) Gt(rhs *TfheCiphertext) (*TfheCiphertext, error) { return C.gt_fhe_uint64(lhs, rhs, sks), nil }, fheUint160BinaryNotSupportedOp, + fheUint2048BinaryNotSupportedOp, true) } @@ -1811,7 +1948,7 @@ func (lhs *TfheCiphertext) ScalarGt(rhs *big.Int) (*TfheCiphertext, error) { }, func(lhs unsafe.Pointer, rhs C.uint64_t) (unsafe.Pointer, error) { return C.scalar_gt_fhe_uint64(lhs, rhs, sks), nil - }, fheUint160BinaryScalarNotSupportedOp, + }, fheUint160BinaryScalarNotSupportedOp, fheUint2048BinarScalaryNotSupportedOp, true) } @@ -1834,6 +1971,7 @@ func (lhs *TfheCiphertext) Le(rhs *TfheCiphertext) (*TfheCiphertext, error) { return C.le_fhe_uint64(lhs, rhs, sks), nil }, fheUint160BinaryNotSupportedOp, + fheUint2048BinaryNotSupportedOp, true) } @@ -1856,7 +1994,7 @@ func (lhs *TfheCiphertext) ScalarLe(rhs *big.Int) (*TfheCiphertext, error) { func(lhs unsafe.Pointer, rhs C.uint64_t) (unsafe.Pointer, error) { return C.scalar_le_fhe_uint64(lhs, rhs, sks), nil }, - fheUint160BinaryScalarNotSupportedOp, + fheUint160BinaryScalarNotSupportedOp, fheUint2048BinarScalaryNotSupportedOp, true) } @@ -1879,6 +2017,7 @@ func (lhs *TfheCiphertext) Lt(rhs *TfheCiphertext) (*TfheCiphertext, error) { return C.lt_fhe_uint64(lhs, rhs, sks), nil }, fheUint160BinaryNotSupportedOp, + fheUint2048BinaryNotSupportedOp, true) } @@ -1900,7 +2039,7 @@ func (lhs *TfheCiphertext) ScalarLt(rhs *big.Int) (*TfheCiphertext, error) { func(lhs unsafe.Pointer, rhs C.uint64_t) (unsafe.Pointer, error) { return C.scalar_lt_fhe_uint64(lhs, rhs, sks), nil }, - fheUint160BinaryScalarNotSupportedOp, + fheUint160BinaryScalarNotSupportedOp, fheUint2048BinarScalaryNotSupportedOp, true) } @@ -1922,7 +2061,7 @@ func (lhs *TfheCiphertext) Min(rhs *TfheCiphertext) (*TfheCiphertext, error) { func(lhs unsafe.Pointer, rhs unsafe.Pointer) (unsafe.Pointer, error) { return C.min_fhe_uint64(lhs, rhs, sks), nil }, - fheUint160BinaryNotSupportedOp, false) + fheUint160BinaryNotSupportedOp, fheUint2048BinaryNotSupportedOp, false) } func (lhs *TfheCiphertext) ScalarMin(rhs *big.Int) (*TfheCiphertext, error) { @@ -1943,7 +2082,7 @@ func (lhs *TfheCiphertext) ScalarMin(rhs *big.Int) (*TfheCiphertext, error) { func(lhs unsafe.Pointer, rhs C.uint64_t) (unsafe.Pointer, error) { return C.scalar_min_fhe_uint64(lhs, rhs, sks), nil }, - fheUint160BinaryScalarNotSupportedOp, false) + fheUint160BinaryScalarNotSupportedOp, fheUint2048BinarScalaryNotSupportedOp, false) } func (lhs *TfheCiphertext) Max(rhs *TfheCiphertext) (*TfheCiphertext, error) { @@ -1964,7 +2103,7 @@ func (lhs *TfheCiphertext) Max(rhs *TfheCiphertext) (*TfheCiphertext, error) { func(lhs unsafe.Pointer, rhs unsafe.Pointer) (unsafe.Pointer, error) { return C.max_fhe_uint64(lhs, rhs, sks), nil }, - fheUint160BinaryNotSupportedOp, false) + fheUint160BinaryNotSupportedOp, fheUint2048BinaryNotSupportedOp, false) } func (lhs *TfheCiphertext) ScalarMax(rhs *big.Int) (*TfheCiphertext, error) { @@ -1985,7 +2124,7 @@ func (lhs *TfheCiphertext) ScalarMax(rhs *big.Int) (*TfheCiphertext, error) { func(lhs unsafe.Pointer, rhs C.uint64_t) (unsafe.Pointer, error) { return C.scalar_max_fhe_uint64(lhs, rhs, sks), nil }, - fheUint160BinaryScalarNotSupportedOp, false) + fheUint160BinaryScalarNotSupportedOp, fheUint2048BinarScalaryNotSupportedOp, false) } func (lhs *TfheCiphertext) Neg() (*TfheCiphertext, error) { @@ -2491,6 +2630,10 @@ func (ct *TfheCiphertext) CastTo(castToType FheUintType) (*TfheCiphertext, error default: panic("castTo: unexpected type to cast to") } + case FheUint160: + return castFheUint160To(ct, castToType) + default: + panic("castTo: unexpected type to cast from") } res.computeHash() return res, nil @@ -2572,7 +2715,20 @@ func (ct *TfheCiphertext) Decrypt() (big.Int, error) { return *new(big.Int).SetUint64(0), errors.New("failed to decrypt FheUint160") } C.destroy_fhe_uint160(ptr) - resultBigInt := *u256ToBigInt(result) + resultBigInt := *u256ToBigInt(&result) + return resultBigInt, nil + case FheUint2048: + ptr := C.deserialize_fhe_uint2048(toDynamicBufferView(ct.Serialization)) + if ptr == nil { + return *new(big.Int).SetUint64(0), errors.New("failed to deserialize FheUint2048") + } + var result C.U2048 + ret = C.decrypt_fhe_uint2048(cks, ptr, &result) + if ret != 0 { + return *new(big.Int).SetUint64(0), errors.New("failed to decrypt FheUint160") + } + C.destroy_fhe_uint2048(ptr) + resultBigInt := *u2048ToBigInt(&result) return resultBigInt, nil default: panic("decrypt: unexpected ciphertext type") @@ -2585,6 +2741,8 @@ func (ct *TfheCiphertext) Decrypt() (big.Int, error) { func (ct *TfheCiphertext) computeHash() { hash := common.BytesToHash(crypto.Keccak256(ct.Serialization)) + hash[31] = HashVersion + hash[30] = byte(ct.FheUintType) ct.Hash = &hash } diff --git a/fhevm/tfhe/tfhe_key_management.go b/fhevm/tfhe/tfhe_key_management.go index b3828c3..1fcdf33 100644 --- a/fhevm/tfhe/tfhe_key_management.go +++ b/fhevm/tfhe/tfhe_key_management.go @@ -24,14 +24,6 @@ func GetExpandedFheCiphertextSize(t FheUintType) (size uint, found bool) { 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 @@ -64,7 +56,6 @@ func InitGlobalKeysWithNewKeys() { func initCiphertextSizes() { ExpandedFheCiphertextSize = make(map[FheUintType]uint) - compactFheCiphertextSize = make(map[FheUintType]uint) ExpandedFheCiphertextSize[FheBool] = uint(len(new(TfheCiphertext).TrivialEncrypt(*big.NewInt(0), FheBool).Serialize())) ExpandedFheCiphertextSize[FheUint4] = uint(len(new(TfheCiphertext).TrivialEncrypt(*big.NewInt(0), FheUint4).Serialize())) @@ -73,14 +64,7 @@ func initCiphertextSizes() { 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[FheUint160] = uint(len(new(TfheCiphertext).TrivialEncrypt(*big.NewInt(0), FheUint160).Serialize())) - - compactFheCiphertextSize[FheBool] = uint(len(EncryptAndSerializeCompact(0, FheBool))) - compactFheCiphertextSize[FheUint4] = uint(len(EncryptAndSerializeCompact(0, FheUint4))) - compactFheCiphertextSize[FheUint8] = uint(len(EncryptAndSerializeCompact(0, FheUint8))) - compactFheCiphertextSize[FheUint16] = uint(len(EncryptAndSerializeCompact(0, FheUint16))) - compactFheCiphertextSize[FheUint32] = uint(len(EncryptAndSerializeCompact(0, FheUint32))) - compactFheCiphertextSize[FheUint64] = uint(len(EncryptAndSerializeCompact(0, FheUint64))) - compactFheCiphertextSize[FheUint160] = uint(len(EncryptAndSerializeCompact(0, FheUint160))) + ExpandedFheCiphertextSize[FheUint2048] = uint(len(new(TfheCiphertext).TrivialEncrypt(*big.NewInt(0), FheUint2048).Serialize())) } func InitGlobalKeysFromFiles(keysDir string) error { diff --git a/fhevm/tfhe/tfhe_test.go b/fhevm/tfhe/tfhe_test.go index ed0fa8f..22b08cc 100644 --- a/fhevm/tfhe/tfhe_test.go +++ b/fhevm/tfhe/tfhe_test.go @@ -882,6 +882,14 @@ func TfheEq(t *testing.T, fheUintType FheUintType) { } a.SetBytes(byteValue) b.SetBytes(byteValue) + case FheUint2048: + hexValue := "12345676876661323221435343778899" + byteValue, err := hex.DecodeString(hexValue) + if err != nil { + log.Fatalf("Failed to decode hex string: %v", err) + } + a.SetBytes(byteValue) + b.SetBytes(byteValue) } var expected uint64 @@ -892,6 +900,7 @@ func TfheEq(t *testing.T, fheUintType FheUintType) { expected = 0 } + // TODO: use encryption for FheUint2048 when available in tfhe-rs ctA := new(TfheCiphertext) ctA.Encrypt(a, fheUintType) ctB := new(TfheCiphertext) @@ -973,6 +982,14 @@ func TfheNe(t *testing.T, fheUintType FheUintType) { } a.SetBytes(byteValue) b.SetUint64(8888) + case FheUint2048: + hexValue := "12345676876661323221435343990055" + byteValue, err := hex.DecodeString(hexValue) + if err != nil { + log.Fatalf("Failed to decode hex string: %v", err) + } + a.SetBytes(byteValue) + b.SetUint64(8888) } var expected uint64 @@ -982,6 +999,7 @@ func TfheNe(t *testing.T, fheUintType FheUintType) { } else { expected = 1 } + // TODO: use encryption for FheUint2048 when available in tfhe-rs ctA := new(TfheCiphertext) ctA.Encrypt(a, fheUintType) ctB := new(TfheCiphertext) @@ -1734,6 +1752,65 @@ func TestTfheEqArrayUnsupportedType(t *testing.T) { } } +func TfheCompact160ListSerDeserRoundTrip(t *testing.T, input []big.Int) { + serList, err := EncryptAndSerializeCompact160List(input) + if err != nil { + t.Fatalf("EncryptAndSerializeCompact160List failed with %v", err) + } + cts, err := DeserializeAndExpandCompact160List(serList) + if err != nil { + t.Fatalf("DeserializeAndExpandCompact160List failed with %v", err) + } + if len(cts) != len(input) { + t.Fatalf("DeserializeAndExpandCompact160List returned %d ciphertexts, expected %d", len(cts), len(input)) + } + + for i, ct := range cts { + v, err := ct.Decrypt() + if err != nil { + t.Fatalf("Decrypt of ct%d failed with %v", i, err) + } + if v.Cmp(&input[i]) != 0 { + t.Fatalf("v%d=%v is not equa to in%d=%v", i, v, i, input[i]) + } + } +} + +func TestTfheCompact160ListSerDeserRoundTrip64Bit(t *testing.T) { + input := make([]big.Int, 0) + input = append(input, *big.NewInt(79)) + input = append(input, *big.NewInt(42)) + TfheCompact160ListSerDeserRoundTrip(t, input) +} + +func TestTfheCompact160ListSerDeserRoundTrip160Bit(t *testing.T) { + input := make([]big.Int, 0) + in1, ok := new(big.Int).SetString("1edd3edac274a90128356fb8caa11bd2", 16) + if in1 == nil || !ok { + t.Fatalf("failed to create 128 bit integer") + } + in2, ok := new(big.Int).SetString("9f24d93621347ca0832d1a3980750eea", 16) + if in2 == nil || !ok { + t.Fatalf("failed to create 128 bit integer") + } + in3, ok := new(big.Int).SetString("e80e81fe4402389034f8123d4d2fffe9", 16) + if in3 == nil || !ok { + t.Fatalf("failed to create 128 bit integer") + } + input = append(input, *in1) + input = append(input, *in2) + input = append(input, *in3) + TfheCompact160ListSerDeserRoundTrip(t, input) +} + +func TestTfheCompact160ListEmptyInput(t *testing.T) { + input := make([]big.Int, 0) + _, err := EncryptAndSerializeCompact160List(input) + if err == nil { + t.Fatalf("EncryptAndSerializeCompact160List must have failed on empty input") + } +} + func TestTfheEncryptDecryptBool(t *testing.T) { TfheEncryptDecrypt(t, FheBool) } @@ -2338,6 +2415,10 @@ func TestTfheEq160(t *testing.T) { TfheEq(t, FheUint160) } +func TestTfheEq2048(t *testing.T) { + TfheEq(t, FheUint2048) +} + func TestTfheScalarEq4(t *testing.T) { TfheScalarEq(t, FheUint4) } @@ -2386,6 +2467,10 @@ func TestTfheNe160(t *testing.T) { TfheNe(t, FheUint160) } +func TestTfheNe2048(t *testing.T) { + TfheNe(t, FheUint2048) +} + func TestTfheScalarNe4(t *testing.T) { TfheScalarNe(t, FheUint4) } diff --git a/fhevm/tfhe/tfhe_wrappers.c b/fhevm/tfhe/tfhe_wrappers.c index 823f413..37cde13 100644 --- a/fhevm/tfhe/tfhe_wrappers.c +++ b/fhevm/tfhe/tfhe_wrappers.c @@ -365,6 +365,18 @@ void* deserialize_fhe_uint160(DynamicBufferView in) { return ct; } +int serialize_fhe_uint2048(void *ct, DynamicBuffer* out) { + return fhe_uint2048_serialize(ct, out); +} + +void* deserialize_fhe_uint2048(DynamicBufferView in) { + FheUint2048* ct = NULL; + const int r = fhe_uint2048_deserialize(in, &ct); + if(r != 0) { + return NULL; + } + return ct; +} void* deserialize_compact_fhe_uint160(DynamicBufferView in) { CompactFheUint160List* list = NULL; @@ -391,6 +403,31 @@ void* deserialize_compact_fhe_uint160(DynamicBufferView in) { return ct; } +void* deserialize_compact_fhe_uint2048(DynamicBufferView in) { + CompactFheUint2048List* list = NULL; + FheUint2048* ct = NULL; + + int r = compact_fhe_uint2048_list_deserialize(in, &list); + if(r != 0) { + return NULL; + } + size_t len = 0; + r = compact_fhe_uint2048_list_len(list, &len); + // Expect only 1 ciphertext in the list. + if(r != 0 || len != 1) { + r = compact_fhe_uint2048_list_destroy(list); + assert(r == 0); + return NULL; + } + r = compact_fhe_uint2048_list_expand(list, &ct, 1); + if(r != 0) { + ct = NULL; + } + r = compact_fhe_uint2048_list_destroy(list); + assert(r == 0); + return ct; +} + void destroy_fhe_bool(void* ct) { const int r = fhe_bool_destroy(ct); assert(r == 0); @@ -426,6 +463,11 @@ void destroy_fhe_uint160(void* ct) { assert(r == 0); } +void destroy_fhe_uint2048(void* ct) { + const int r = fhe_uint2048_destroy(ct); + assert(r == 0); +} + void* add_fhe_uint4(void* ct1, void* ct2, void* sks) { FheUint4* result = NULL; @@ -1570,6 +1612,17 @@ void* eq_fhe_uint160(void* ct1, void* ct2, void* sks) return result; } +void* eq_fhe_uint2048(void* ct1, void* ct2, void* sks) +{ + FheBool* result = NULL; + + checked_set_server_key(sks); + + const int r = fhe_uint2048_eq(ct1, ct2, &result); + if(r != 0) return NULL; + return result; +} + void* scalar_eq_fhe_uint4(void* ct, uint8_t pt, void* sks) { FheBool* result = NULL; @@ -1636,6 +1689,17 @@ void* scalar_eq_fhe_uint160(void* ct, struct U256 pt, void* sks) return result; } +void* scalar_eq_fhe_uint2048(void* ct, struct U2048 pt, void* sks) +{ + FheBool* result = NULL; + + checked_set_server_key(sks); + + const int r = fhe_uint2048_scalar_eq(ct, pt, &result); + if(r != 0) return NULL; + return result; +} + void* eq_fhe_array_uint4(void* ct1, size_t ct1_len, void* ct2, size_t ct2_len, void* sks) { FheBool* result = NULL; @@ -1757,6 +1821,17 @@ void* ne_fhe_uint160(void* ct1, void* ct2, void* sks) return result; } +void* ne_fhe_uint2048(void* ct1, void* ct2, void* sks) +{ + FheBool* result = NULL; + + checked_set_server_key(sks); + + const int r = fhe_uint2048_ne(ct1, ct2, &result); + if(r != 0) return NULL; + return result; +} + void* scalar_ne_fhe_uint4(void* ct, uint8_t pt, void* sks) { FheBool* result = NULL; @@ -1823,6 +1898,17 @@ void* scalar_ne_fhe_uint160(void* ct, struct U256 pt, void* sks) return result; } +void* scalar_ne_fhe_uint2048(void* ct, struct U2048 pt, void* sks) +{ + FheBool* result = NULL; + + checked_set_server_key(sks); + + const int r = fhe_uint2048_scalar_ne(ct, pt, &result); + if(r != 0) return NULL; + return result; +} + void* ge_fhe_uint4(void* ct1, void* ct2, void* sks) { FheBool* result = NULL; @@ -2700,6 +2786,10 @@ int decrypt_fhe_uint160(void* cks, void* ct, struct U256 *res) return fhe_uint160_decrypt(ct, cks, res); } +int decrypt_fhe_uint2048(void* cks, void* ct, struct U2048* res) { + return fhe_uint2048_decrypt(ct, cks, res); +} + void* public_key_encrypt_fhe_bool(void* pks, bool value) { CompactFheBoolList* list = NULL; FheBool* ct = NULL; @@ -2812,6 +2902,15 @@ void* public_key_encrypt_fhe_uint160(void* pks, struct U256 *value) { return ct; } +void* public_key_encrypt_fhe_uint2048(void* pks, struct U2048 *value) { + FheUint2048* ct = NULL; + + int r = fhe_uint2048_try_encrypt_with_compact_public_key_u2048(*value, pks, &ct); + assert(r == 0); + + return ct; +} + void* trivial_encrypt_fhe_bool(void* sks, bool value) { FheBool* ct = NULL; @@ -2878,12 +2977,23 @@ void* trivial_encrypt_fhe_uint64(void* sks, uint64_t value) { return ct; } -void* trivial_encrypt_fhe_uint160(void* sks, struct U256 value) { +void* trivial_encrypt_fhe_uint160(void* sks, struct U256* value) { FheUint160* ct = NULL; checked_set_server_key(sks); - int r = fhe_uint160_try_encrypt_trivial_u256(value, &ct); + int r = fhe_uint160_try_encrypt_trivial_u256(*value, &ct); + assert(r == 0); + + return ct; +} + +void* trivial_encrypt_fhe_uint2048(void* sks, struct U2048* value) { + FheUint2048* ct = NULL; + + checked_set_server_key(sks); + + int r = fhe_uint2048_try_encrypt_trivial_u2048(*value, &ct); assert(r == 0); return ct; @@ -2981,6 +3091,20 @@ void public_key_encrypt_and_serialize_fhe_uint160_list(void* pks, struct U256 *v assert(r == 0); } +void public_key_encrypt_and_serialize_fhe_uint2048_list(void* pks, struct U2048 *value, DynamicBuffer* out) { + CompactFheUint2048List* list = NULL; + FheUint2048* ct = NULL; + + int r = compact_fhe_uint2048_list_try_encrypt_with_compact_public_key_u2048(value, 1, pks, &list); + assert(r == 0); + + r = compact_fhe_uint2048_list_serialize(list, out); + assert(r == 0); + + r = compact_fhe_uint2048_list_destroy(list); + assert(r == 0); +} + void* cast_4_8(void* ct, void* sks) { FheUint8* result = NULL; @@ -3180,3 +3304,53 @@ void* cast_64_32(void* ct, void* sks) { if(r != 0) return NULL; return result; } + +void* cast_160_4(void* ct, void* sks) { + FheUint4* result = NULL; + + checked_set_server_key(sks); + + const int r = fhe_uint160_cast_into_fhe_uint4(ct, &result); + if(r != 0) return NULL; + return result; +} + +void* cast_160_8(void* ct, void* sks) { + FheUint8* result = NULL; + + checked_set_server_key(sks); + + const int r = fhe_uint160_cast_into_fhe_uint8(ct, &result); + if(r != 0) return NULL; + return result; +} + +void* cast_160_16(void* ct, void* sks) { + FheUint16* result = NULL; + + checked_set_server_key(sks); + + const int r = fhe_uint160_cast_into_fhe_uint16(ct, &result); + if(r != 0) return NULL; + return result; +} + +void* cast_160_32(void* ct, void* sks) { + FheUint32* result = NULL; + + checked_set_server_key(sks); + + const int r = fhe_uint160_cast_into_fhe_uint32(ct, &result); + if(r != 0) return NULL; + return result; +} + +void* cast_160_64(void* ct, void* sks) { + FheUint64* result = NULL; + + checked_set_server_key(sks); + + const int r = fhe_uint160_cast_into_fhe_uint64(ct, &result); + if(r != 0) return NULL; + return result; +} diff --git a/fhevm/tfhe/tfhe_wrappers.go b/fhevm/tfhe/tfhe_wrappers.go index 2fc2c8c..19d7e72 100644 --- a/fhevm/tfhe/tfhe_wrappers.go +++ b/fhevm/tfhe/tfhe_wrappers.go @@ -44,6 +44,8 @@ func serialize(ptr unsafe.Pointer, t FheUintType) ([]byte, error) { ret = C.serialize_fhe_uint64(ptr, out) case FheUint160: ret = C.serialize_fhe_uint160(ptr, out) + case FheUint2048: + ret = C.serialize_fhe_uint2048(ptr, out) default: panic("serialize: unexpected ciphertext type") } @@ -89,14 +91,19 @@ func EncryptAndSerializeCompact(value uint64, fheUintType FheUintType) []byte { case FheUint64: C.public_key_encrypt_and_serialize_fhe_uint64_list(pks, C.uint64_t(value), out) case FheUint160: - // TODO - // This function is used to compute ciphertext size, the given value is generally 0, value_big := new(big.Int).SetUint64(value) input, err := bigIntToU256(value_big) if err != nil { panic(err) } C.public_key_encrypt_and_serialize_fhe_uint160_list(pks, input, out) + case FheUint2048: + value_big := new(big.Int).SetUint64(value) + input, err := bigIntToU2048(value_big) + if err != nil { + panic(err) + } + C.public_key_encrypt_and_serialize_fhe_uint2048_list(pks, input, out) } ser := C.GoBytes(unsafe.Pointer(out.pointer), C.int(out.length)) @@ -104,33 +111,244 @@ func EncryptAndSerializeCompact(value uint64, fheUintType FheUintType) []byte { return ser } -// bigIntToU256 uses u256_from_big_endian_bytes to convert big.Int to U256 +// bigIntToU256 uses x to convert big.Int to U256 func bigIntToU256(value *big.Int) (*C.U256, error) { // Convert big.Int to 32-byte big-endian slice - bytes := value.Bytes() - if len(bytes) > 32 { + if len(value.Bytes()) > 32 { return nil, fmt.Errorf("big.Int too large for U256") } - paddedBytes := make([]byte, 32-len(bytes)) // Padding - paddedBytes = append(paddedBytes, bytes...) + bytes := make([]byte, 32) + value.FillBytes(bytes) var result C.U256 + ret := C.u256_from_big_endian_bytes((*C.uint8_t)(unsafe.Pointer(&bytes[0])), C.size_t(32), &result) + if ret != 0 { + return nil, fmt.Errorf("failed to convert big.Int to U256: %d", ret) + } + return &result, nil +} - _, err := C.u256_from_big_endian_bytes((*C.uint8_t)(unsafe.Pointer(&paddedBytes[0])), C.size_t(32), &result) - if err != nil { - return nil, fmt.Errorf("failed to convert big.Int to U256: %v", err) +func bigIntToU2048(value *big.Int) (*C.U2048, error) { + if len(value.Bytes()) > 256 { + return nil, fmt.Errorf("big.Int too large for U2048") } + bytes := make([]byte, 256) + value.FillBytes(bytes) + var result C.U2048 + ret := C.U2048_from_big_endian_bytes((*C.uint8_t)(unsafe.Pointer(&bytes[0])), C.size_t(256), &result) + if ret != 0 { + return nil, fmt.Errorf("failed to convert big.Int to U2048: %d", ret) + } return &result, nil } // u256ToBigInt converts a U256 to a *big.Int. -func u256ToBigInt(u256 C.U256) *big.Int { +func u256ToBigInt(value *C.U256) *big.Int { // Allocate a byte slice with enough space (32 bytes for U256) buf := make([]byte, 32) // Call the C function to fill the buffer with the big-endian bytes of U256 - C.u256_big_endian_bytes(u256, (*C.uint8_t)(unsafe.Pointer(&buf[0])), C.size_t(len(buf))) + C.u256_big_endian_bytes(*value, (*C.uint8_t)(unsafe.Pointer(&buf[0])), C.size_t(len(buf))) return new(big.Int).SetBytes(buf) } + +func u2048ToBigInt(value *C.U2048) *big.Int { + buf := make([]byte, 256) + C.U2048_big_endian_bytes(*value, (*C.uint8_t)(unsafe.Pointer(&buf[0])), C.size_t(len(buf))) + return new(big.Int).SetBytes(buf) +} + +func EncryptAndSerializeCompact160List(values []big.Int) ([]byte, error) { + if len(values) == 0 { + return nil, fmt.Errorf("EncryptAndSerializeCompact160List empty array given") + } + inputArray := make([]C.U256, len(values)) + for i, v := range values { + u256, err := bigIntToU256(&v) + if err != nil { + return nil, err + } + inputArray[i] = *u256 + } + + var list *C.CompactFheUint160List + ret := C.compact_fhe_uint160_list_try_encrypt_with_compact_public_key_u256(&inputArray[0], (C.size_t)(len(inputArray)), (*C.CompactPublicKey)(pks), &list) + if ret != 0 { + return nil, fmt.Errorf("EncryptAndSerializeCompact160List failed to encrypt with %d", ret) + } + defer C.compact_fhe_uint160_list_destroy(list) + + ser := C.DynamicBuffer{} + ret = C.compact_fhe_uint160_list_serialize(list, &ser) + if ret != 0 { + return nil, fmt.Errorf("EncryptAndSerializeCompact160List failed to serialize with %d", ret) + } + defer C.destroy_dynamic_buffer(&ser) + + return C.GoBytes(unsafe.Pointer(ser.pointer), C.int(ser.length)), nil +} + +func DeserializeAndExpandCompact160List(in []byte) ([]*TfheCiphertext, error) { + var list *C.CompactFheUint160List + ret := C.compact_fhe_uint160_list_deserialize(toDynamicBufferView(in), &list) + if ret != 0 { + return nil, fmt.Errorf("DeserializeCompact160List failed to deserialize list with %d", ret) + } + defer C.compact_fhe_uint160_list_destroy(list) + + var len C.size_t + ret = C.compact_fhe_uint160_list_len(list, &len) + if ret != 0 { + return nil, fmt.Errorf("DeserializeCompact160List failed to get list length with %d", ret) + } + if len == 0 { + return nil, fmt.Errorf("DeserializeCompact160List length is 0") + } + + expanded := make([]*C.FheUint160, len) + ret = C.compact_fhe_uint160_list_expand(list, &expanded[0], len) + if ret != 0 { + return nil, fmt.Errorf("DeserializeCompact160List failed to expand list with %d", ret) + } + defer func() { + for _, c := range expanded { + C.destroy_fhe_uint160(unsafe.Pointer(c)) + } + }() + + cts := make([]*TfheCiphertext, 0, len) + for _, c := range expanded { + ser, err := serialize(unsafe.Pointer(c), FheUint160) + if err != nil { + return nil, err + } + ct := new(TfheCiphertext) + ct.Serialization = ser + ct.FheUintType = FheUint160 + ct.computeHash() + cts = append(cts, ct) + } + return cts, nil +} + +func EncryptAndSerializeCompact2048List(values []big.Int) ([]byte, error) { + if len(values) == 0 { + return nil, fmt.Errorf("EncryptAndSerializeCompact2048List empty array given") + } + inputArray := make([]C.U2048, len(values)) + for i, v := range values { + u2048, err := bigIntToU2048(&v) + if err != nil { + return nil, err + } + inputArray[i] = *u2048 + } + + var list *C.CompactFheUint2048List + ret := C.compact_fhe_uint2048_list_try_encrypt_with_compact_public_key_u2048(&inputArray[0], (C.size_t)(len(inputArray)), (*C.CompactPublicKey)(pks), &list) + if ret != 0 { + return nil, fmt.Errorf("EncryptAndSerializeCompact2048List failed to encrypt with %d", ret) + } + defer C.compact_fhe_uint2048_list_destroy(list) + + ser := C.DynamicBuffer{} + ret = C.compact_fhe_uint2048_list_serialize(list, &ser) + if ret != 0 { + return nil, fmt.Errorf("EncryptAndSerializeCompact2048List failed to serialize with %d", ret) + } + defer C.destroy_dynamic_buffer(&ser) + + return C.GoBytes(unsafe.Pointer(ser.pointer), C.int(ser.length)), nil +} + +func DeserializeAndExpandCompact2048List(in []byte) ([]*TfheCiphertext, error) { + var list *C.CompactFheUint2048List + ret := C.compact_fhe_uint2048_list_deserialize(toDynamicBufferView(in), &list) + if ret != 0 { + return nil, fmt.Errorf("DeserializeCompact2048List failed to deserialize list with %d", ret) + } + defer C.compact_fhe_uint2048_list_destroy(list) + + var len C.size_t + ret = C.compact_fhe_uint2048_list_len(list, &len) + if ret != 0 { + return nil, fmt.Errorf("DeserializeCompact2048List failed to get list length with %d", ret) + } + if len == 0 { + return nil, fmt.Errorf("DeserializeCompact2048List length is 0") + } + + expanded := make([]*C.FheUint2048, len) + ret = C.compact_fhe_uint2048_list_expand(list, &expanded[0], len) + if ret != 0 { + return nil, fmt.Errorf("DeserializeCompact2048List failed to expand list with %d", ret) + } + defer func() { + for _, c := range expanded { + C.destroy_fhe_uint2048(unsafe.Pointer(c)) + } + }() + + cts := make([]*TfheCiphertext, 0, len) + for _, c := range expanded { + ser, err := serialize(unsafe.Pointer(c), FheUint2048) + if err != nil { + return nil, err + } + ct := new(TfheCiphertext) + ct.Serialization = ser + ct.FheUintType = FheUint2048 + ct.computeHash() + cts = append(cts, ct) + } + return cts, nil +} + +func castFheUint160To(ct *TfheCiphertext, fheUintType FheUintType) (*TfheCiphertext, error) { + ptr160 := C.deserialize_fhe_uint160(toDynamicBufferView(ct.Serialize())) + if ptr160 == nil { + return nil, errors.New("CastFheUint160To failed to deserialize FheUint160 ciphertext") + } + defer C.destroy_fhe_uint160(ptr160) + + var err error + var resPtr unsafe.Pointer + switch fheUintType { + case FheBool: + var ctNe *TfheCiphertext + ctNe, err = ct.ScalarNe(big.NewInt(0)) + if err != nil { + return nil, err + } + ctNe.computeHash() + return ctNe, nil + case FheUint4: + resPtr = C.cast_160_4(ptr160, sks) + defer C.destroy_fhe_uint4(resPtr) + case FheUint8: + resPtr = C.cast_160_8(ptr160, sks) + defer C.destroy_fhe_uint8(resPtr) + case FheUint16: + resPtr = C.cast_160_16(ptr160, sks) + defer C.destroy_fhe_uint16(resPtr) + case FheUint32: + resPtr = C.cast_160_32(ptr160, sks) + defer C.destroy_fhe_uint32(resPtr) + case FheUint64: + resPtr = C.cast_160_64(ptr160, sks) + defer C.destroy_fhe_uint64(resPtr) + default: + return nil, fmt.Errorf("castFheUint160To invalid type to FheUint160 to: %s", fheUintType.String()) + } + + res := new(TfheCiphertext) + res.Serialization, err = serialize(resPtr, fheUintType) + if err != nil { + return nil, err + } + res.FheUintType = fheUintType + res.computeHash() + return res, nil +} diff --git a/fhevm/tfhe/tfhe_wrappers.h b/fhevm/tfhe/tfhe_wrappers.h index 6597255..7e79e3b 100644 --- a/fhevm/tfhe/tfhe_wrappers.h +++ b/fhevm/tfhe/tfhe_wrappers.h @@ -57,10 +57,16 @@ void* deserialize_compact_fhe_uint64(DynamicBufferView in); int serialize_fhe_uint160(void *ct, DynamicBuffer* out); +int serialize_fhe_uint2048(void *ct, DynamicBuffer* out); + void* deserialize_fhe_uint160(DynamicBufferView in); +void* deserialize_fhe_uint2048(DynamicBufferView in); + void* deserialize_compact_fhe_uint160(DynamicBufferView in); +void* deserialize_compact_fhe_uint2048(DynamicBufferView in); + void destroy_fhe_bool(void* ct); void destroy_fhe_uint4(void* ct); @@ -75,6 +81,8 @@ void destroy_fhe_uint64(void* ct); void destroy_fhe_uint160(void* ct); +void destroy_fhe_uint2048(void* ct); + void* add_fhe_uint4(void* ct1, void* ct2, void* sks); void* add_fhe_uint8(void* ct1, void* ct2, void* sks); @@ -283,6 +291,8 @@ void* eq_fhe_uint64(void* ct1, void* ct2, void* sks); void* eq_fhe_uint160(void* ct1, void* ct2, void* sks); +void* eq_fhe_uint2048(void* ct1, void* ct2, void* sks); + void* scalar_eq_fhe_uint4(void* ct, uint8_t pt, void* sks); void* scalar_eq_fhe_uint8(void* ct, uint8_t pt, void* sks); @@ -295,6 +305,8 @@ void* scalar_eq_fhe_uint64(void* ct, uint64_t pt, void* sks); void* scalar_eq_fhe_uint160(void* ct, struct U256 pt, void* sks); +void* scalar_eq_fhe_uint2048(void* ct, struct U2048 pt, void* sks); + void* eq_fhe_array_uint4(void* ct1, size_t ct1_len, void* ct2, size_t ct2_len, void* sks); void* eq_fhe_array_uint8(void* ct1, size_t ct1_len, void* ct2, size_t ct2_len, void* sks); @@ -317,6 +329,8 @@ void* ne_fhe_uint64(void* ct1, void* ct2, void* sks); void* ne_fhe_uint160(void* ct1, void* ct2, void* sks); +void* ne_fhe_uint2048(void* ct1, void* ct2, void* sks); + void* scalar_ne_fhe_uint4(void* ct, uint8_t pt, void* sks); void* scalar_ne_fhe_uint8(void* ct, uint8_t pt, void* sks); @@ -329,6 +343,8 @@ void* scalar_ne_fhe_uint64(void* ct, uint64_t pt, void* sks); void* scalar_ne_fhe_uint160(void* ct, struct U256 pt, void* sks); +void* scalar_ne_fhe_uint2048(void* ct, struct U2048 pt, void* sks); + void* ge_fhe_uint4(void* ct1, void* ct2, void* sks); void* ge_fhe_uint8(void* ct1, void* ct2, void* sks); @@ -495,7 +511,9 @@ int decrypt_fhe_uint32(void* cks, void* ct, uint32_t* res); int decrypt_fhe_uint64(void* cks, void* ct, uint64_t* res); -int decrypt_fhe_uint160(void* cks, void* ct, struct U256 *res); +int decrypt_fhe_uint160(void* cks, void* ct, struct U256* res); + +int decrypt_fhe_uint2048(void* cks, void* ct, struct U2048* res); void* public_key_encrypt_fhe_bool(void* pks, bool value); @@ -511,6 +529,8 @@ void* public_key_encrypt_fhe_uint64(void* pks, uint64_t value); void* public_key_encrypt_fhe_uint160(void* pks, struct U256 *value); +void* public_key_encrypt_fhe_uint2048(void* pks, struct U2048 *value); + void* trivial_encrypt_fhe_bool(void* sks, bool value); void* trivial_encrypt_fhe_uint4(void* sks, uint8_t value); @@ -523,7 +543,9 @@ void* trivial_encrypt_fhe_uint32(void* sks, uint32_t value); void* trivial_encrypt_fhe_uint64(void* sks, uint64_t value); -void* trivial_encrypt_fhe_uint160(void* sks, struct U256 value); +void* trivial_encrypt_fhe_uint160(void* sks, struct U256* value); + +void* trivial_encrypt_fhe_uint2048(void* sks, struct U2048* value); void public_key_encrypt_and_serialize_fhe_bool_list(void* pks, bool value, DynamicBuffer* out); @@ -539,6 +561,8 @@ void public_key_encrypt_and_serialize_fhe_uint64_list(void* pks, uint64_t value, void public_key_encrypt_and_serialize_fhe_uint160_list(void* pks, struct U256 *value, DynamicBuffer* out); +void public_key_encrypt_and_serialize_fhe_uint2048_list(void* pks, struct U2048 *value, DynamicBuffer* out); + void* cast_bool_4(void* ct, void* sks); void* cast_bool_8(void* ct, void* sks); @@ -598,3 +622,13 @@ void* cast_64_8(void* ct, void* sks); void* cast_64_16(void* ct, void* sks); void* cast_64_32(void* ct, void* sks); + +void* cast_160_4(void* ct, void* sks); + +void* cast_160_8(void* ct, void* sks); + +void* cast_160_16(void* ct, void* sks); + +void* cast_160_32(void* ct, void* sks); + +void* cast_160_64(void* ct, void* sks); diff --git a/tfhe-rs b/tfhe-rs index 46115eb..f3b89e8 160000 --- a/tfhe-rs +++ b/tfhe-rs @@ -1 +1 @@ -Subproject commit 46115eb9616ddaba2ae30509853e99891c44348d +Subproject commit f3b89e83d741cf89a8277a98eb0f2665987ee456