diff --git a/fhevm-engine/Cargo.lock b/fhevm-engine/Cargo.lock index 1cf2b692..8be91644 100644 --- a/fhevm-engine/Cargo.lock +++ b/fhevm-engine/Cargo.lock @@ -5124,9 +5124,9 @@ dependencies = [ [[package]] name = "tfhe" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81923c2433f461e35f3d0b933696335e4f03b874438c844c576eab99e302fe00" +checksum = "51a86dd06c50cf4f8e39712b41d0a3f19804ed7c6f7ad77d60d759aa7910b470" dependencies = [ "aligned-vec", "bincode", diff --git a/fhevm-engine/coprocessor/Cargo.toml b/fhevm-engine/coprocessor/Cargo.toml index 28e587b1..3825bae9 100644 --- a/fhevm-engine/coprocessor/Cargo.toml +++ b/fhevm-engine/coprocessor/Cargo.toml @@ -4,9 +4,9 @@ version = "0.1.0" edition = "2021" [target.'cfg(target_arch = "x86_64")'.dependencies] -tfhe = { version = "0.8.0", features = ["boolean", "shortint", "integer", "x86_64-unix", "zk-pok", "experimental-force_fft_algo_dif4"] } +tfhe = { version = "0.8.2", features = ["boolean", "shortint", "integer", "x86_64-unix", "zk-pok", "experimental-force_fft_algo_dif4"] } [target.'cfg(target_arch = "aarch64")'.dependencies] -tfhe = { version = "0.8.0", features = ["boolean", "shortint", "integer", "aarch64-unix", "zk-pok", "experimental-force_fft_algo_dif4"] } +tfhe = { version = "0.8.2", features = ["boolean", "shortint", "integer", "aarch64-unix", "zk-pok", "experimental-force_fft_algo_dif4"] } [dependencies] # Common dependencies diff --git a/fhevm-engine/coprocessor/src/db_queries.rs b/fhevm-engine/coprocessor/src/db_queries.rs index faede0c1..5d4112c8 100644 --- a/fhevm-engine/coprocessor/src/db_queries.rs +++ b/fhevm-engine/coprocessor/src/db_queries.rs @@ -1,5 +1,6 @@ use std::collections::{BTreeSet, HashMap}; use std::str::FromStr; +use std::sync::Arc; use crate::server::GrpcTracer; use crate::types::{CoprocessorError, TfheTenantKeys}; @@ -109,6 +110,7 @@ pub struct FetchTenantKeyResult { pub verifying_contract_address: String, pub acl_contract_address: String, pub server_key: tfhe::ServerKey, + pub public_params: Arc, } /// Returns chain id and verifying contract address for EIP712 signature and tfhe server key @@ -130,6 +132,7 @@ where verifying_contract_address: key.verifying_contract_address.clone(), acl_contract_address: key.acl_contract_address.clone(), server_key: key.sks.clone(), + public_params: key.public_params.clone(), }); } } @@ -169,7 +172,7 @@ where tenant_id: key.tenant_id, sks, pks, - public_params, + public_params: Arc::new(public_params), chain_id: key.chain_id, acl_contract_address: key.acl_contract_address, verifying_contract_address: key.verifying_contract_address, diff --git a/fhevm-engine/coprocessor/src/server.rs b/fhevm-engine/coprocessor/src/server.rs index 71206921..3e19dc7c 100644 --- a/fhevm-engine/coprocessor/src/server.rs +++ b/fhevm-engine/coprocessor/src/server.rs @@ -372,6 +372,7 @@ impl CoprocessorService { let cloned_input = ci.clone(); let server_key = server_key.clone(); let tracer = tracer.clone(); + let public_params = fetch_key_response.public_params.clone(); let mut blocking_span = tracer.child_span("blocking_ciphertext_list_expand"); blocking_span.set_attributes(vec![KeyValue::new("idx", idx as i64)]); @@ -389,11 +390,12 @@ impl CoprocessorService { span.end(); let mut span = tracer.child_span("expand_ciphertext_list"); - let expanded = try_expand_ciphertext_list(&cloned_input.input_payload) - .map_err(|e| { - let err: Box<(dyn std::error::Error + Send + Sync)> = Box::new(e); - (err, idx) - })?; + let expanded = + try_expand_ciphertext_list(&cloned_input.input_payload, &public_params) + .map_err(|e| { + let err: Box<(dyn std::error::Error + Send + Sync)> = Box::new(e); + (err, idx) + })?; span.set_attributes(vec![ KeyValue::new("idx", idx as i64), diff --git a/fhevm-engine/coprocessor/src/types.rs b/fhevm-engine/coprocessor/src/types.rs index f848b6b9..f28fb683 100644 --- a/fhevm-engine/coprocessor/src/types.rs +++ b/fhevm-engine/coprocessor/src/types.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use fhevm_engine_common::types::FhevmError; #[derive(Debug)] @@ -184,5 +186,5 @@ pub struct TfheTenantKeys { #[allow(dead_code)] pub pks: tfhe::CompactPublicKey, #[allow(dead_code)] - pub public_params: tfhe::zk::CompactPkePublicParams, + pub public_params: Arc, } diff --git a/fhevm-engine/executor/Cargo.toml b/fhevm-engine/executor/Cargo.toml index 6aec0673..b6fcae52 100644 --- a/fhevm-engine/executor/Cargo.toml +++ b/fhevm-engine/executor/Cargo.toml @@ -4,9 +4,9 @@ version = "0.1.0" edition = "2021" [target.'cfg(target_arch = "x86_64")'.dependencies] -tfhe = { version = "0.8.0", features = ["boolean", "shortint", "integer", "x86_64-unix", "zk-pok", "experimental-force_fft_algo_dif4"] } +tfhe = { version = "0.8.2", features = ["boolean", "shortint", "integer", "x86_64-unix", "zk-pok", "experimental-force_fft_algo_dif4"] } [target.'cfg(target_arch = "aarch64")'.dependencies] -tfhe = { version = "0.8.0", features = ["boolean", "shortint", "integer", "aarch64-unix", "zk-pok", "experimental-force_fft_algo_dif4"] } +tfhe = { version = "0.8.2", features = ["boolean", "shortint", "integer", "aarch64-unix", "zk-pok", "experimental-force_fft_algo_dif4"] } [dependencies] clap.workspace = true diff --git a/fhevm-engine/executor/src/server.rs b/fhevm-engine/executor/src/server.rs index 62e4c10e..f1e64ac8 100644 --- a/fhevm-engine/executor/src/server.rs +++ b/fhevm-engine/executor/src/server.rs @@ -16,7 +16,7 @@ use fhevm_engine_common::{ types::{get_ct_type, FhevmError, Handle, SupportedFheCiphertexts, HANDLE_LEN, SCALAR_LEN}, }; use sha3::{Digest, Keccak256}; -use tfhe::{integer::U256, set_server_key}; +use tfhe::{integer::U256, set_server_key, zk::CompactPkePublicParams}; use tokio::task::spawn_blocking; use tonic::{transport::Server, Code, Request, Response, Status}; @@ -64,7 +64,9 @@ pub struct ComputationState { pub ciphertexts: HashMap, } -struct FhevmExecutorService {} +struct FhevmExecutorService { + keys: FhevmKeys, +} #[tonic::async_trait] impl FhevmExecutor for FhevmExecutorService { @@ -72,12 +74,15 @@ impl FhevmExecutor for FhevmExecutorService { &self, req: Request, ) -> Result, Status> { + let public_params = self.keys.public_params.clone(); let resp = spawn_blocking(move || { let req = req.get_ref(); let mut state = ComputationState::default(); // Exapnd compact ciphertext lists for the whole request. - if Self::expand_compact_lists(&req.compact_ciphertext_lists, &mut state).is_err() { + if Self::expand_compact_lists(&req.compact_ciphertext_lists, &mut state, &public_params) + .is_err() + { return SyncComputeResponse { resp: Some(Resp::Error(SyncComputeError::BadInputList.into())), }; @@ -129,7 +134,9 @@ impl FhevmExecutor for FhevmExecutorService { impl FhevmExecutorService { fn new() -> Self { - FhevmExecutorService {} + FhevmExecutorService { + keys: SerializedFhevmKeys::load_from_disk().into(), + } } #[allow(dead_code)] @@ -157,9 +164,10 @@ impl FhevmExecutorService { fn expand_compact_lists( lists: &Vec>, state: &mut ComputationState, + public_params: &CompactPkePublicParams, ) -> Result<(), FhevmError> { for list in lists { - let cts = try_expand_ciphertext_list(&list)?; + let cts = try_expand_ciphertext_list(&list, &public_params)?; let list_hash: Handle = Keccak256::digest(list).to_vec(); for (i, ct) in cts.iter().enumerate() { let mut handle = list_hash.clone(); diff --git a/fhevm-engine/fhevm-engine-common/Cargo.toml b/fhevm-engine/fhevm-engine-common/Cargo.toml index 51999856..237f8d1f 100644 --- a/fhevm-engine/fhevm-engine-common/Cargo.toml +++ b/fhevm-engine/fhevm-engine-common/Cargo.toml @@ -4,9 +4,9 @@ version = "0.1.0" edition = "2021" [target.'cfg(target_arch = "x86_64")'.dependencies] -tfhe = { version = "0.8.0", features = ["boolean", "shortint", "integer", "x86_64-unix", "zk-pok", "experimental-force_fft_algo_dif4"] } +tfhe = { version = "0.8.2", features = ["boolean", "shortint", "integer", "x86_64-unix", "zk-pok", "experimental-force_fft_algo_dif4"] } [target.'cfg(target_arch = "aarch64")'.dependencies] -tfhe = { version = "0.8.0", features = ["boolean", "shortint", "integer", "aarch64-unix", "zk-pok", "experimental-force_fft_algo_dif4"] } +tfhe = { version = "0.8.2", features = ["boolean", "shortint", "integer", "aarch64-unix", "zk-pok", "experimental-force_fft_algo_dif4"] } [dependencies] sha3.workspace = true diff --git a/fhevm-engine/fhevm-engine-common/src/keys.rs b/fhevm-engine/fhevm-engine-common/src/keys.rs index 1db05b16..efe5bad9 100644 --- a/fhevm-engine/fhevm-engine-common/src/keys.rs +++ b/fhevm-engine/fhevm-engine-common/src/keys.rs @@ -1,10 +1,13 @@ -use std::fs::read; +use std::{fs::read, sync::Arc}; use tfhe::{ generate_keys, set_server_key, - shortint::parameters::{ - list_compression::COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, - PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, + shortint::{ + parameters::{ + list_compression::COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, + CompressionParameters, PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, + }, + ClassicPBSParameters, }, zk::{CompactPkeCrs, CompactPkePublicParams}, ClientKey, CompactPublicKey, ConfigBuilder, ServerKey, @@ -12,13 +15,17 @@ use tfhe::{ use crate::utils::{safe_deserialize_key, safe_serialize_key}; +pub const TFHE_PARAMS: ClassicPBSParameters = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; +pub const TFHE_COMPRESSION_PARAMS: CompressionParameters = + COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + pub const MAX_BITS_TO_PROVE: usize = 2048; pub struct FhevmKeys { pub server_key: ServerKey, pub client_key: Option, pub compact_public_key: CompactPublicKey, - pub public_params: CompactPkePublicParams, + pub public_params: Arc, } pub struct SerializedFhevmKeys { @@ -31,10 +38,9 @@ pub struct SerializedFhevmKeys { impl FhevmKeys { pub fn new() -> Self { println!("Generating keys..."); - let config = - ConfigBuilder::with_custom_parameters(PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64) - .enable_compression(COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64) - .build(); + let config = ConfigBuilder::with_custom_parameters(TFHE_PARAMS) + .enable_compression(TFHE_COMPRESSION_PARAMS) + .build(); let (client_key, server_key) = generate_keys(config); let compact_public_key = CompactPublicKey::new(&client_key); let crs = CompactPkeCrs::from_config(config, MAX_BITS_TO_PROVE).expect("CRS creation"); @@ -42,7 +48,7 @@ impl FhevmKeys { server_key, client_key: Some(client_key), compact_public_key, - public_params: crs.public_params().clone(), + public_params: Arc::new(crs.public_params().clone()), } } @@ -98,7 +104,7 @@ impl From for SerializedFhevmKeys { server_key: safe_serialize_key(&f.server_key), client_key: f.client_key.map(|c| safe_serialize_key(&c)), compact_public_key: safe_serialize_key(&f.compact_public_key), - public_params: safe_serialize_key(&f.public_params), + public_params: safe_serialize_key(f.public_params.as_ref()), } } } @@ -112,8 +118,9 @@ impl From for FhevmKeys { .map(|c| safe_deserialize_key(&c).expect("deserialize client key")), compact_public_key: safe_deserialize_key(&f.compact_public_key) .expect("deserialize compact public key"), - public_params: safe_deserialize_key(&f.public_params) - .expect("deserialize public params"), + public_params: Arc::new( + safe_deserialize_key(&f.public_params).expect("deserialize public params"), + ), } } } diff --git a/fhevm-engine/fhevm-engine-common/src/tfhe_ops.rs b/fhevm-engine/fhevm-engine-common/src/tfhe_ops.rs index 2b9bcab0..8f6e0e9f 100644 --- a/fhevm-engine/fhevm-engine-common/src/tfhe_ops.rs +++ b/fhevm-engine/fhevm-engine-common/src/tfhe_ops.rs @@ -1,16 +1,22 @@ use crate::{ + keys::TFHE_PARAMS, types::{ is_ebytes_type, FheOperationType, FhevmError, SupportedFheCiphertexts, SupportedFheOperations, }, - utils::safe_deserialize, + utils::{safe_deserialize, safe_deserialize_conformant}, }; use tfhe::{ - integer::{bigint::StaticUnsignedBigInt, U256}, + integer::{ + bigint::StaticUnsignedBigInt, + ciphertext::IntegerProvenCompactCiphertextListConformanceParams, U256, + }, prelude::{ CastInto, CiphertextList, FheEq, FheMax, FheMin, FheOrd, FheTryTrivialEncrypt, IfThenElse, RotateLeft, RotateRight, }, + shortint::parameters::CompactPublicKeyEncryptionParameters, + zk::CompactPkePublicParams, FheBool, FheUint1024, FheUint128, FheUint16, FheUint160, FheUint2, FheUint2048, FheUint256, FheUint32, FheUint4, FheUint512, FheUint64, FheUint8, Seed, }; @@ -266,10 +272,19 @@ pub fn current_ciphertext_version() -> i16 { pub fn try_expand_ciphertext_list( input_ciphertext: &[u8], + public_params: &CompactPkePublicParams, ) -> Result, FhevmError> { let mut res = Vec::new(); - let the_list: tfhe::ProvenCompactCiphertextList = safe_deserialize(input_ciphertext)?; + let pk_params = CompactPublicKeyEncryptionParameters::try_from(TFHE_PARAMS) + .map_err(|_| FhevmError::MissingTfheRsData)?; + + let the_list: tfhe::ProvenCompactCiphertextList = safe_deserialize_conformant( + input_ciphertext, + &IntegerProvenCompactCiphertextListConformanceParams::from_public_key_encryption_parameters_and_crs_parameters( + pk_params, public_params, + ), + )?; let expanded = the_list .expand_without_verification() @@ -284,96 +299,120 @@ pub fn try_expand_ciphertext_list( tfhe::FheTypes::Bool => { let ct: tfhe::FheBool = expanded .get(idx) - .expect("Index must exist") - .expect("Must succeed, we just checked this is the type"); + .map_err(|e| FhevmError::DeserializationError(e.into()))? + .ok_or(FhevmError::DeserializationError( + "failed to get expected data type".into(), + ))?; res.push(SupportedFheCiphertexts::FheBool(ct)); } tfhe::FheTypes::Uint4 => { let ct: tfhe::FheUint4 = expanded .get(idx) - .expect("Index must exist") - .expect("Must succeed, we just checked this is the type"); + .map_err(|e| FhevmError::DeserializationError(e.into()))? + .ok_or(FhevmError::DeserializationError( + "failed to get expected data type".into(), + ))?; res.push(SupportedFheCiphertexts::FheUint4(ct)); } tfhe::FheTypes::Uint8 => { let ct: tfhe::FheUint8 = expanded .get(idx) - .expect("Index must exist") - .expect("Must succeed, we just checked this is the type"); + .map_err(|e| FhevmError::DeserializationError(e.into()))? + .ok_or(FhevmError::DeserializationError( + "failed to get expected data type".into(), + ))?; res.push(SupportedFheCiphertexts::FheUint8(ct)); } tfhe::FheTypes::Uint16 => { let ct: tfhe::FheUint16 = expanded .get(idx) - .expect("Index must exist") - .expect("Must succeed, we just checked this is the type"); + .map_err(|e| FhevmError::DeserializationError(e.into()))? + .ok_or(FhevmError::DeserializationError( + "failed to get expected data type".into(), + ))?; res.push(SupportedFheCiphertexts::FheUint16(ct)); } tfhe::FheTypes::Uint32 => { let ct: tfhe::FheUint32 = expanded .get(idx) - .expect("Index must exist") - .expect("Must succeed, we just checked this is the type"); + .map_err(|e| FhevmError::DeserializationError(e.into()))? + .ok_or(FhevmError::DeserializationError( + "failed to get expected data type".into(), + ))?; res.push(SupportedFheCiphertexts::FheUint32(ct)); } tfhe::FheTypes::Uint64 => { let ct: tfhe::FheUint64 = expanded .get(idx) - .expect("Index must exist") - .expect("Must succeed, we just checked this is the type"); + .map_err(|e| FhevmError::DeserializationError(e.into()))? + .ok_or(FhevmError::DeserializationError( + "failed to get expected data type".into(), + ))?; res.push(SupportedFheCiphertexts::FheUint64(ct)); } tfhe::FheTypes::Uint128 => { let ct: tfhe::FheUint128 = expanded .get(idx) - .expect("Index must exist") - .expect("Must succeed, we just checked this is the type"); + .map_err(|e| FhevmError::DeserializationError(e.into()))? + .ok_or(FhevmError::DeserializationError( + "failed to get expected data type".into(), + ))?; res.push(SupportedFheCiphertexts::FheUint128(ct)); } tfhe::FheTypes::Uint160 => { let ct: tfhe::FheUint160 = expanded .get(idx) - .expect("Index must exist") - .expect("Must succeed, we just checked this is the type"); + .map_err(|e| FhevmError::DeserializationError(e.into()))? + .ok_or(FhevmError::DeserializationError( + "failed to get expected data type".into(), + ))?; res.push(SupportedFheCiphertexts::FheUint160(ct)); } tfhe::FheTypes::Uint256 => { let ct: tfhe::FheUint256 = expanded .get(idx) - .expect("Index must exist") - .expect("Must succeed, we just checked this is the type"); + .map_err(|e| FhevmError::DeserializationError(e.into()))? + .ok_or(FhevmError::DeserializationError( + "failed to get expected data type".into(), + ))?; res.push(SupportedFheCiphertexts::FheUint256(ct)); } tfhe::FheTypes::Uint512 => { let ct: tfhe::FheUint512 = expanded .get(idx) - .expect("Index must exist") - .expect("Must succeed, we just checked this is the type"); + .map_err(|e| FhevmError::DeserializationError(e.into()))? + .ok_or(FhevmError::DeserializationError( + "failed to get expected data type".into(), + ))?; res.push(SupportedFheCiphertexts::FheBytes64(ct)); } tfhe::FheTypes::Uint1024 => { let ct: tfhe::FheUint1024 = expanded .get(idx) - .expect("Index must exist") - .expect("Must succeed, we just checked this is the type"); + .map_err(|e| FhevmError::DeserializationError(e.into()))? + .ok_or(FhevmError::DeserializationError( + "failed to get expected data type".into(), + ))?; res.push(SupportedFheCiphertexts::FheBytes128(ct)); } tfhe::FheTypes::Uint2048 => { let ct: tfhe::FheUint2048 = expanded .get(idx) - .expect("Index must exist") - .expect("Must succeed, we just checked this is the type"); + .map_err(|e| FhevmError::DeserializationError(e.into()))? + .ok_or(FhevmError::DeserializationError( + "failed to get expected data type".into(), + ))?; res.push(SupportedFheCiphertexts::FheBytes256(ct)); } diff --git a/fhevm-engine/fhevm-engine-common/src/utils.rs b/fhevm-engine/fhevm-engine-common/src/utils.rs index 4d8de908..1742b751 100644 --- a/fhevm-engine/fhevm-engine-common/src/utils.rs +++ b/fhevm-engine/fhevm-engine-common/src/utils.rs @@ -1,5 +1,5 @@ use serde::{de::DeserializeOwned, Serialize}; -use tfhe::{named::Named, Unversionize, Versionize}; +use tfhe::{named::Named, prelude::ParameterSetConformant, Unversionize, Versionize}; use crate::types::FhevmError; @@ -20,6 +20,20 @@ pub fn safe_deserialize( .map_err(|e| FhevmError::DeserializationError(e.into())) } +pub fn safe_deserialize_conformant< + T: DeserializeOwned + Named + Unversionize + ParameterSetConformant, +>( + input: &[u8], + parameter_set: &T::ParameterSet, +) -> Result { + tfhe::safe_serialization::safe_deserialize_conformant( + input, + SAFE_SER_DESER_LIMIT, + parameter_set, + ) + .map_err(|e| FhevmError::DeserializationError(e.into())) +} + pub fn safe_serialize_key(object: &T) -> Vec { let mut out = vec![]; tfhe::safe_serialization::safe_serialize(object, &mut out, SAFE_SER_DESER_KEY_LIMIT)