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..a464e5c 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,54 @@ 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") + } + ciphertextHash := crypto.Keccak256Hash(ciphertext).Bytes() + handles = make([][32]byte, 0) + for i := range types { + index := byte(i) + handle := crypto.Keccak256Hash(append(ciphertextHash, 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") + } + ciphertextHash := crypto.Keccak256Hash(ciphertext).Bytes() + handles = make([][32]byte, 0) + for i := range types { + index := byte(i + 25) + handle := crypto.Keccak256Hash(append(ciphertextHash, 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, fheUintType tfhe.FheUintType) []byte { + input, err := verifyCipertextMethod.Inputs.Pack(handle, [20]byte{}, ciphertext, [1]byte{byte(fheUintType)}) + if err != nil { + panic(err) + } + return input } func loadCiphertextInTestMemory(environment EVMEnvironment, value uint64, depth int, t tfhe.FheUintType) *tfhe.TfheCiphertext { @@ -254,77 +294,193 @@ 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, fheUintType) + 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, fheUintType) + 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 TestVerifyCiphertextBadType(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 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 - 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] + // put a bad type in the handle + handle[30] = 255 + input := packInputList(handle, ciphertext, tfhe.FheUint32) _, 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 bad type in handle") } - 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 TestVerifyCiphertextTypeMismatchInHandle(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 different type in the handle + handle[30] = byte(tfhe.FheUint16) + input := packInputList(handle, ciphertext, tfhe.FheUint32) + _, err := verifyCiphertextRun(environment, addr, addr, input, readOnly, nil) + if err == nil { + t.Fatalf("verifyCiphertext must have failed on type mismatch 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.FheUint32) + _, 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.FheUint32) + _, 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 +1943,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 +2512,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 +3668,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 +3703,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 +3755,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 +4324,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 +4344,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 +4372,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 +4883,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 +4924,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 +4945,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..c4dec87 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,164 @@ 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. + 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]) + + // 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 handle type matches the input type. + if handleType != inputType { + return [32]byte{}, nil, fmt.Errorf("parseVerifyCiphertextInput handle type (%d) is different from the input type (%d)", handleType, inputType) + } + + // Make sure hash in the handle is correct. + ciphertextListHash := crypto.Keccak256Hash(ciphertextList) + ciphertextListAndIndexHash := crypto.Keccak256Hash(append(ciphertextListHash.Bytes(), handleIndex)) + if !bytes.Equal(ciphertextListAndIndexHash[:29], handle[:29]) { + return [32]byte{}, nil, fmt.Errorf("parseVerifyCiphertextInput input hash doesn't match handle hash") } - ct := new(tfhe.TfheCiphertext) - err := ct.DeserializeCompact(ctBytes, ctType) + 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.FheUint2048 { + cts, err = tfhe.DeserializeAndExpandCompact2048List(ciphertextList) + } else { + cts, err = tfhe.DeserializeAndExpandCompact160List(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 +} + +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 +434,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 +489,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