From aeb36ee14f5f5af3eb07165008ca3ddb39e201cb Mon Sep 17 00:00:00 2001 From: tmontaigu Date: Mon, 22 Jan 2024 11:32:03 +0100 Subject: [PATCH] fix(integer): is_scalar_out_of_bounds handles bigger ct Fix a bug where in is_scalar_out_of_bounds, if the scalar was negative and the ciphertext a signed one with more blocks than the decomposed scalar, we would do an out of bound access (i.e a panic). This fixes that, this will fix doing signed_overflowing_mul on 256 bits where the bug first appeared --- .../radix_parallel/scalar_comparison.rs | 6 +++++- .../radix_parallel/tests_cases_comparisons.rs | 19 +++++++++++++++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/tfhe/src/integer/server_key/radix_parallel/scalar_comparison.rs b/tfhe/src/integer/server_key/radix_parallel/scalar_comparison.rs index 799bb547cf..8195c61ebd 100644 --- a/tfhe/src/integer/server_key/radix_parallel/scalar_comparison.rs +++ b/tfhe/src/integer/server_key/radix_parallel/scalar_comparison.rs @@ -1,4 +1,3 @@ -// use itertools::Itertools; use super::ServerKey; use crate::integer::block_decomposition::{BlockDecomposer, DecomposableInto}; @@ -56,6 +55,11 @@ impl ServerKey { // If scalar is negative, and that any bits above the ct's n-1 bits is not set // it means scalar is smaller. + if ct.blocks().len() > scalar_blocks.len() { + // Ciphertext has more blocks, the scalar may be in range + return None; + } + // (returns false for empty iter) let at_least_one_block_is_not_full_of_1s = scalar_blocks[ct.blocks().len()..] .iter() diff --git a/tfhe/src/integer/server_key/radix_parallel/tests_cases_comparisons.rs b/tfhe/src/integer/server_key/radix_parallel/tests_cases_comparisons.rs index df5f0261e7..9dde626b98 100644 --- a/tfhe/src/integer/server_key/radix_parallel/tests_cases_comparisons.rs +++ b/tfhe/src/integer/server_key/radix_parallel/tests_cases_comparisons.rs @@ -1,3 +1,4 @@ +use crate::core_crypto::prelude::misc::divide_ceil; use crate::integer::ciphertext::{RadixCiphertext, SignedRadixCiphertext}; use crate::integer::keycache::KEY_CACHE; use crate::integer::{IntegerKeyKind, ServerKey, I256, U256}; @@ -1276,12 +1277,12 @@ create_parametrized_test!(integer_unchecked_scalar_comparisons_edge { fn integer_is_scalar_out_of_bounds(param: ClassicPBSParameters) { let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix); - let num_block = (128f64 / (param.message_modulus.0 as f64).log(2.0)).ceil() as usize; + let num_block = divide_ceil(128usize, param.message_modulus.0.ilog2() as usize); - let mut rng = rand::thread_rng(); + let mut rng = thread_rng(); - let clear_0 = rng.gen::(); - let ct = cks.encrypt_radix(clear_0, num_block); + let clear_unsigned = rng.gen::(); + let ct = cks.encrypt_radix(clear_unsigned, num_block); // Positive scalars { @@ -1328,6 +1329,16 @@ fn integer_is_scalar_out_of_bounds(param: ClassicPBSParameters) { let res = sks.is_scalar_out_of_bounds(&ct, scalar); assert_eq!(res, Some(std::cmp::Ordering::Less)); } + + // Negative scalar + { + // Case where scalar will have less blocks when decomposed than + // the ciphertext has + let bigger_ct = cks.encrypt_signed_radix(-1i128, num_block); + let scalar = i64::MIN; + let res = sks.is_scalar_out_of_bounds(&bigger_ct, scalar); + assert_eq!(res, None); + } } create_parametrized_test!(integer_is_scalar_out_of_bounds {