Skip to content

Commit

Permalink
feat: make ciphertext inputs global per request
Browse files Browse the repository at this point in the history
Instead of passing in ciphertexts as part of the SyncInput, pass them
globally for the whole request. Decompress them into a map that lives
for the duration of the request. Computations then refer to ciphertexts
in the map via handles, applying to inputs, compressed ciphertexts and
results.

Above also allows for use of results as inputs in subsequent
computations.
  • Loading branch information
dartdart26 committed Aug 30, 2024
1 parent 112ce72 commit cc72203
Show file tree
Hide file tree
Showing 4 changed files with 258 additions and 81 deletions.
61 changes: 43 additions & 18 deletions fhevm-engine/executor/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ use executor::{
fhevm_executor_server::{FhevmExecutor, FhevmExecutorServer},
sync_compute_response::Resp,
sync_input::Input,
Ciphertext, ResultCiphertexts, SyncComputation, SyncComputeError, SyncComputeRequest,
CompressedCiphertext, ResultCiphertexts, SyncComputation, SyncComputeError, SyncComputeRequest,
SyncComputeResponse, SyncInput,
};
use fhevm_engine_common::{
keys::{FhevmKeys, SerializedFhevmKeys},
tfhe_ops::{current_ciphertext_version, perform_fhe_operation, try_expand_ciphertext_list},
types::{FhevmError, Handle, SupportedFheCiphertexts, HANDLE_LEN, SCALAR_LEN},
types::{get_ct_type, FhevmError, Handle, SupportedFheCiphertexts, HANDLE_LEN, SCALAR_LEN},
};
use sha3::{Digest, Keccak256};
use tfhe::{integer::U256, set_server_key};
Expand Down Expand Up @@ -77,15 +77,26 @@ impl FhevmExecutor for FhevmExecutorService {
SERVER_KEY_IS_SET.set(true);
}

// Exapnd inputs that are global to the whole request.
let req = req.get_ref();
let mut state = ComputationState::default();
if Self::expand_inputs(&req.input_lists, &keys, &mut state).is_err() {

// Exapnd compact ciphertext lists for the whole request.
if Self::expand_compact_lists(&req.compact_ciphertext_lists, &keys, &mut state).is_err()
{
return SyncComputeResponse {
resp: Some(Resp::Error(SyncComputeError::BadInputList.into())),
};
}

// Decompress compressed ciphertexts for the whole request.
if Self::decompress_compressed_ciphertexts(&req.compressed_ciphertexts, &mut state)
.is_err()
{
return SyncComputeResponse {
resp: Some(Resp::Error(SyncComputeError::BadInputCiphertext.into())),
};
}

// Execute all computations.
let mut result_cts = Vec::new();
for computation in &req.computations {
Expand Down Expand Up @@ -127,7 +138,7 @@ impl FhevmExecutorService {
fn process_computation(
comp: &SyncComputation,
state: &mut ComputationState,
) -> Result<Vec<Ciphertext>, SyncComputeError> {
) -> Result<Vec<CompressedCiphertext>, SyncComputeError> {
// For now, assume only one result handle.
let result_handle = comp
.result_handles
Expand All @@ -145,7 +156,7 @@ impl FhevmExecutorService {
}
}

fn expand_inputs(
fn expand_compact_lists(
lists: &Vec<Vec<u8>>,
keys: &FhevmKeys,
state: &mut ComputationState,
Expand All @@ -170,25 +181,43 @@ impl FhevmExecutorService {
Ok(())
}

fn decompress_compressed_ciphertexts(
cts: &Vec<CompressedCiphertext>,
state: &mut ComputationState,
) -> Result<(), Box<dyn Error>> {
for ct in cts.iter() {
let ct_type = get_ct_type(&ct.handle)?;
let supported_ct = SupportedFheCiphertexts::decompress(ct_type, &ct.serialization)?;
state.ciphertexts.insert(
ct.handle.clone(),
InMemoryCiphertext {
expanded: supported_ct,
compressed: ct.serialization.clone(),
},
);
}
Ok(())
}

fn get_ciphertext(
comp: &SyncComputation,
result_handle: &Handle,
state: &ComputationState,
) -> Result<Vec<Ciphertext>, SyncComputeError> {
) -> Result<Vec<CompressedCiphertext>, SyncComputeError> {
match (comp.inputs.first(), comp.inputs.len()) {
(
Some(SyncInput {
input: Some(Input::InputHandle(handle)),
input: Some(Input::Handle(handle)),
}),
1,
) => {
if let Some(in_mem_ciphertext) = state.ciphertexts.get(handle) {
if *handle != *result_handle {
Err(SyncComputeError::BadInputs)
} else {
Ok(vec![Ciphertext {
Ok(vec![CompressedCiphertext {
handle: result_handle.to_vec(),
ciphertext: in_mem_ciphertext.compressed.clone(),
serialization: in_mem_ciphertext.compressed.clone(),
}])
}
} else {
Expand All @@ -203,18 +232,14 @@ impl FhevmExecutorService {
comp: &SyncComputation,
result_handle: Handle,
state: &mut ComputationState,
) -> Result<Vec<Ciphertext>, SyncComputeError> {
) -> Result<Vec<CompressedCiphertext>, SyncComputeError> {
// Collect computation inputs.
let inputs: Result<Vec<SupportedFheCiphertexts>, Box<dyn Error>> = comp
.inputs
.iter()
.map(|sync_input| match &sync_input.input {
Some(input) => match input {
Input::Ciphertext(c) if c.handle.len() == HANDLE_LEN => {
let ct_type = c.handle[30] as i16;
Ok(SupportedFheCiphertexts::decompress(ct_type, &c.ciphertext)?)
}
Input::InputHandle(h) => {
Input::Handle(h) => {
let ct = state.ciphertexts.get(h).ok_or(FhevmError::BadInputs)?;
Ok(ct.expanded.clone())
}
Expand All @@ -241,9 +266,9 @@ impl FhevmExecutorService {
compressed: compressed.clone(),
},
);
Ok(vec![Ciphertext {
Ok(vec![CompressedCiphertext {
handle: result_handle,
ciphertext: compressed,
serialization: compressed,
}])
}
Err(_) => Err(SyncComputeError::ComputationFailed),
Expand Down
Loading

0 comments on commit cc72203

Please sign in to comment.