mirror of
https://github.com/zama-ai/tfhe-rs.git
synced 2026-01-10 07:08:03 -05:00
fix(integer): handles compression of empty ct in empty list
This commit is contained in:
committed by
Nicolas Sarlin
parent
21efad5fae
commit
0996604574
@@ -64,13 +64,12 @@ impl CompressedCiphertextListBuilder {
|
||||
{
|
||||
let n = self.ciphertexts.len();
|
||||
let kind = data.compress_into(&mut self.ciphertexts);
|
||||
let message_modulus = self.ciphertexts.last().unwrap().message_modulus;
|
||||
assert_eq!(n + kind.num_blocks(message_modulus), self.ciphertexts.len());
|
||||
|
||||
if kind.num_blocks(message_modulus) != 0 {
|
||||
self.info.push(kind);
|
||||
}
|
||||
|
||||
let num_blocks = self
|
||||
.ciphertexts
|
||||
.last()
|
||||
.map_or(0, |ct| kind.num_blocks(ct.message_modulus));
|
||||
assert_eq!(n + num_blocks, self.ciphertexts.len());
|
||||
self.info.push(kind);
|
||||
self
|
||||
}
|
||||
|
||||
|
||||
@@ -145,7 +145,16 @@ impl crate::integer::ciphertext::Expandable for FheString {
|
||||
) -> crate::Result<Self> {
|
||||
match kind {
|
||||
DataKind::String { n_chars, padded } => {
|
||||
let n_blocks_per_chars = 7u32.div_ceil(blocks[0].message_modulus.0.ilog2());
|
||||
if n_chars == 0 {
|
||||
return Ok(Self::empty());
|
||||
}
|
||||
|
||||
let Some(first_block) = blocks.first() else {
|
||||
return Err(crate::error!(
|
||||
"Invalid number of blocks for a string of {n_chars} chars, got 0 blocks"
|
||||
));
|
||||
};
|
||||
let n_blocks_per_chars = 7u32.div_ceil(first_block.message_modulus.0.ilog2());
|
||||
let expected_num_blocks = n_chars * n_blocks_per_chars;
|
||||
if expected_num_blocks != blocks.len() as u32 {
|
||||
return Err(crate::error!("Invalid number of blocks for a string of {n_chars} chars, expected {expected_num_blocks}, got {}", blocks.len()));
|
||||
|
||||
@@ -56,3 +56,44 @@ fn test_compressed_list_with_strings() {
|
||||
assert_eq!(decrypted, clear_string2);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compressed_list_empty_string() {
|
||||
let params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128.into();
|
||||
let (cks, _) = gen_keys::<ShortintParameterSet>(params, IntegerKeyKind::Radix);
|
||||
|
||||
let private_compression_key =
|
||||
cks.new_compression_private_key(COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128);
|
||||
|
||||
let (compression_key, decompression_key) =
|
||||
cks.new_compression_decompression_keys(&private_compression_key);
|
||||
|
||||
let cks = StringClientKey::new(cks);
|
||||
|
||||
let clear_empty = String::new();
|
||||
let empty = cks.encrypt_ascii(&clear_empty, None);
|
||||
|
||||
let clear_string = String::from("not empty");
|
||||
let string = cks.encrypt_ascii(&clear_string, None);
|
||||
|
||||
// Try to compress 2 empty strings with one not empty in the middle
|
||||
let mut builder = CompressedCiphertextListBuilder::new();
|
||||
builder.push(empty.clone());
|
||||
builder.push(string);
|
||||
builder.push(empty);
|
||||
let compressed = builder.build(&compression_key);
|
||||
|
||||
assert_eq!(compressed.len(), 3);
|
||||
|
||||
let s1: FheString = compressed.get(0, &decompression_key).unwrap().unwrap();
|
||||
let decrypted = cks.decrypt_ascii(&s1);
|
||||
assert_eq!(decrypted, clear_empty);
|
||||
|
||||
let s2: FheString = compressed.get(1, &decompression_key).unwrap().unwrap();
|
||||
let decrypted = cks.decrypt_ascii(&s2);
|
||||
assert_eq!(decrypted, clear_string);
|
||||
|
||||
let s3: FheString = compressed.get(2, &decompression_key).unwrap().unwrap();
|
||||
let decrypted = cks.decrypt_ascii(&s3);
|
||||
assert_eq!(decrypted, clear_empty);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user