Skip to content

Commit 4284a2e

Browse files
committed
refactor(integer): factorize expansion code
1 parent 075e1b7 commit 4284a2e

File tree

1 file changed

+113
-188
lines changed

1 file changed

+113
-188
lines changed

tfhe/src/integer/ciphertext/compact_list.rs

+113-188
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::integer::encryption::{create_clear_radix_block_iterator, KnowsMessage
99
use crate::integer::parameters::CompactCiphertextListConformanceParams;
1010
pub use crate::integer::parameters::IntegerCompactCiphertextListExpansionMode;
1111
use crate::integer::{CompactPublicKey, ServerKey};
12+
use crate::shortint::ciphertext::Degree;
1213
#[cfg(feature = "zk-pok")]
1314
use crate::shortint::ciphertext::ProvenCompactCiphertextListConformanceParams;
1415
use crate::shortint::parameters::{
@@ -545,6 +546,85 @@ impl IntegerUnpackingToShortintCastingModeHelper {
545546
}
546547
}
547548

549+
type ExpansionHelperCallback<'a, ListType> = &'a dyn Fn(
550+
&ListType,
551+
ShortintCompactCiphertextListCastingMode<'_>,
552+
) -> Result<Vec<Ciphertext>, crate::Error>;
553+
554+
fn expansion_helper<ListType>(
555+
expansion_mode: IntegerCompactCiphertextListExpansionMode<'_>,
556+
ct_list: &ListType,
557+
list_degree: Degree,
558+
info: &[DataKind],
559+
is_packed: bool,
560+
list_expansion_fn: ExpansionHelperCallback<'_, ListType>,
561+
) -> Result<Vec<Ciphertext>, crate::Error> {
562+
if is_packed
563+
&& matches!(
564+
expansion_mode,
565+
IntegerCompactCiphertextListExpansionMode::NoCastingAndNoUnpacking
566+
)
567+
{
568+
return Err(crate::Error::new(String::from(
569+
WRONG_UNPACKING_MODE_ERR_MSG,
570+
)));
571+
}
572+
573+
match expansion_mode {
574+
IntegerCompactCiphertextListExpansionMode::CastAndUnpackIfNecessary(
575+
key_switching_key_view,
576+
) => {
577+
let dest_sks = &key_switching_key_view.key.dest_server_key;
578+
let function_helper = IntegerUnpackingToShortintCastingModeHelper::new(
579+
dest_sks.message_modulus,
580+
dest_sks.carry_modulus,
581+
);
582+
let functions = if is_packed {
583+
function_helper.generate_unpack_and_sanitize_functions(info)
584+
} else {
585+
function_helper.generate_sanitize_without_unpacking_functions(info)
586+
};
587+
588+
list_expansion_fn(
589+
ct_list,
590+
ShortintCompactCiphertextListCastingMode::CastIfNecessary {
591+
casting_key: key_switching_key_view.key,
592+
functions: Some(functions.as_slice()),
593+
},
594+
)
595+
}
596+
IntegerCompactCiphertextListExpansionMode::UnpackAndSanitizeIfNecessary(sks) => {
597+
let expanded_blocks =
598+
list_expansion_fn(ct_list, ShortintCompactCiphertextListCastingMode::NoCasting)?;
599+
600+
if is_packed {
601+
let mut conformance_params = sks.key.conformance_params();
602+
conformance_params.degree = list_degree;
603+
604+
for ct in expanded_blocks.iter() {
605+
if !ct.is_conformant(&conformance_params) {
606+
return Err(crate::Error::new(
607+
"This compact list is not conformant with the given server key"
608+
.to_string(),
609+
));
610+
}
611+
}
612+
613+
Ok(unpack_and_sanitize_message_and_carries(
614+
expanded_blocks,
615+
sks,
616+
info,
617+
))
618+
} else {
619+
Ok(sanitize_boolean_blocks(expanded_blocks, sks, info))
620+
}
621+
}
622+
IntegerCompactCiphertextListExpansionMode::NoCastingAndNoUnpacking => {
623+
list_expansion_fn(ct_list, ShortintCompactCiphertextListCastingMode::NoCasting)
624+
}
625+
}
626+
}
627+
548628
impl CompactCiphertextList {
549629
pub fn is_packed(&self) -> bool {
550630
self.ct_list.degree.get()
@@ -694,66 +774,14 @@ impl CompactCiphertextList {
694774
) -> crate::Result<CompactCiphertextListExpander> {
695775
let is_packed = self.is_packed();
696776

697-
if is_packed
698-
&& matches!(
699-
expansion_mode,
700-
IntegerCompactCiphertextListExpansionMode::NoCastingAndNoUnpacking
701-
)
702-
{
703-
return Err(crate::Error::new(String::from(
704-
WRONG_UNPACKING_MODE_ERR_MSG,
705-
)));
706-
}
707-
708-
let expanded_blocks = match expansion_mode {
709-
IntegerCompactCiphertextListExpansionMode::CastAndUnpackIfNecessary(
710-
key_switching_key_view,
711-
) => {
712-
let dest_sks = &key_switching_key_view.key.dest_server_key;
713-
let function_helper = IntegerUnpackingToShortintCastingModeHelper::new(
714-
dest_sks.message_modulus,
715-
dest_sks.carry_modulus,
716-
);
717-
let functions = if is_packed {
718-
function_helper.generate_unpack_and_sanitize_functions(&self.info)
719-
} else {
720-
function_helper.generate_sanitize_without_unpacking_functions(&self.info)
721-
};
722-
723-
self.ct_list
724-
.expand(ShortintCompactCiphertextListCastingMode::CastIfNecessary {
725-
casting_key: key_switching_key_view.key,
726-
functions: Some(functions.as_slice()),
727-
})?
728-
}
729-
IntegerCompactCiphertextListExpansionMode::UnpackAndSanitizeIfNecessary(sks) => {
730-
let expanded_blocks = self
731-
.ct_list
732-
.expand(ShortintCompactCiphertextListCastingMode::NoCasting)?;
733-
734-
if is_packed {
735-
let degree = self.ct_list.degree;
736-
let mut conformance_params = sks.key.conformance_params();
737-
conformance_params.degree = degree;
738-
739-
for ct in expanded_blocks.iter() {
740-
if !ct.is_conformant(&conformance_params) {
741-
return Err(crate::Error::new(
742-
"This compact list is not conformant with the given server key"
743-
.to_string(),
744-
));
745-
}
746-
}
747-
748-
unpack_and_sanitize_message_and_carries(expanded_blocks, sks, &self.info)
749-
} else {
750-
sanitize_boolean_blocks(expanded_blocks, sks, &self.info)
751-
}
752-
}
753-
IntegerCompactCiphertextListExpansionMode::NoCastingAndNoUnpacking => self
754-
.ct_list
755-
.expand(ShortintCompactCiphertextListCastingMode::NoCasting)?,
756-
};
777+
let expanded_blocks = expansion_helper(
778+
expansion_mode,
779+
&self.ct_list,
780+
self.ct_list.degree,
781+
&self.info,
782+
is_packed,
783+
&crate::shortint::ciphertext::CompactCiphertextList::expand,
784+
)?;
757785

758786
Ok(CompactCiphertextListExpander::new(
759787
expanded_blocks,
@@ -822,78 +850,27 @@ impl ProvenCompactCiphertextList {
822850
) -> crate::Result<CompactCiphertextListExpander> {
823851
let is_packed = self.is_packed();
824852

825-
if is_packed
826-
&& matches!(
853+
// Type annotation needed rust is not able to coerce the type on its own, also forces us to
854+
// use a trait object
855+
let callback: ExpansionHelperCallback<'_, _> = &|ct_list, expansion_mode| {
856+
crate::shortint::ciphertext::ProvenCompactCiphertextList::verify_and_expand(
857+
ct_list,
858+
crs,
859+
&public_key.key,
860+
metadata,
827861
expansion_mode,
828-
IntegerCompactCiphertextListExpansionMode::NoCastingAndNoUnpacking
829862
)
830-
{
831-
return Err(crate::Error::new(String::from(
832-
WRONG_UNPACKING_MODE_ERR_MSG,
833-
)));
834-
}
835-
836-
let expanded_blocks = match expansion_mode {
837-
IntegerCompactCiphertextListExpansionMode::CastAndUnpackIfNecessary(
838-
key_switching_key_view,
839-
) => {
840-
let dest_sks = &key_switching_key_view.key.dest_server_key;
841-
let function_helper = IntegerUnpackingToShortintCastingModeHelper::new(
842-
dest_sks.message_modulus,
843-
dest_sks.carry_modulus,
844-
);
845-
let functions = if is_packed {
846-
function_helper.generate_unpack_and_sanitize_functions(&self.info)
847-
} else {
848-
function_helper.generate_sanitize_without_unpacking_functions(&self.info)
849-
};
850-
self.ct_list.verify_and_expand(
851-
crs,
852-
&public_key.key,
853-
metadata,
854-
ShortintCompactCiphertextListCastingMode::CastIfNecessary {
855-
casting_key: key_switching_key_view.key,
856-
functions: Some(functions.as_slice()),
857-
},
858-
)?
859-
}
860-
IntegerCompactCiphertextListExpansionMode::UnpackAndSanitizeIfNecessary(sks) => {
861-
let expanded_blocks = self.ct_list.verify_and_expand(
862-
crs,
863-
&public_key.key,
864-
metadata,
865-
ShortintCompactCiphertextListCastingMode::NoCasting,
866-
)?;
867-
868-
if is_packed {
869-
let degree = self.ct_list.proved_lists[0].0.degree;
870-
let mut conformance_params = sks.key.conformance_params();
871-
conformance_params.degree = degree;
872-
873-
for ct in expanded_blocks.iter() {
874-
if !ct.is_conformant(&conformance_params) {
875-
return Err(crate::Error::new(
876-
"This compact list is not conformant with the given server key"
877-
.to_string(),
878-
));
879-
}
880-
}
881-
882-
unpack_and_sanitize_message_and_carries(expanded_blocks, sks, &self.info)
883-
} else {
884-
sanitize_boolean_blocks(expanded_blocks, sks, &self.info)
885-
}
886-
}
887-
IntegerCompactCiphertextListExpansionMode::NoCastingAndNoUnpacking => {
888-
self.ct_list.verify_and_expand(
889-
crs,
890-
&public_key.key,
891-
metadata,
892-
ShortintCompactCiphertextListCastingMode::NoCasting,
893-
)?
894-
}
895863
};
896864

865+
let expanded_blocks = expansion_helper(
866+
expansion_mode,
867+
&self.ct_list,
868+
self.ct_list.proved_lists[0].0.degree,
869+
&self.info,
870+
is_packed,
871+
callback,
872+
)?;
873+
897874
Ok(CompactCiphertextListExpander::new(
898875
expanded_blocks,
899876
self.info.clone(),
@@ -910,66 +887,14 @@ impl ProvenCompactCiphertextList {
910887
) -> crate::Result<CompactCiphertextListExpander> {
911888
let is_packed = self.is_packed();
912889

913-
if is_packed
914-
&& matches!(
915-
expansion_mode,
916-
IntegerCompactCiphertextListExpansionMode::NoCastingAndNoUnpacking
917-
)
918-
{
919-
return Err(crate::Error::new(String::from(
920-
WRONG_UNPACKING_MODE_ERR_MSG,
921-
)));
922-
}
923-
924-
let expanded_blocks = match expansion_mode {
925-
IntegerCompactCiphertextListExpansionMode::CastAndUnpackIfNecessary(
926-
key_switching_key_view,
927-
) => {
928-
let dest_sks = &key_switching_key_view.key.dest_server_key;
929-
let function_helper = IntegerUnpackingToShortintCastingModeHelper::new(
930-
dest_sks.message_modulus,
931-
dest_sks.carry_modulus,
932-
);
933-
let functions = if is_packed {
934-
function_helper.generate_unpack_and_sanitize_functions(&self.info)
935-
} else {
936-
function_helper.generate_sanitize_without_unpacking_functions(&self.info)
937-
};
938-
self.ct_list.expand_without_verification(
939-
ShortintCompactCiphertextListCastingMode::CastIfNecessary {
940-
casting_key: key_switching_key_view.key,
941-
functions: Some(functions.as_slice()),
942-
},
943-
)?
944-
}
945-
IntegerCompactCiphertextListExpansionMode::UnpackAndSanitizeIfNecessary(sks) => {
946-
let expanded_blocks = self.ct_list.expand_without_verification(
947-
ShortintCompactCiphertextListCastingMode::NoCasting,
948-
)?;
949-
950-
if is_packed {
951-
let degree = self.ct_list.proved_lists[0].0.degree;
952-
let mut conformance_params = sks.key.conformance_params();
953-
conformance_params.degree = degree;
954-
955-
for ct in expanded_blocks.iter() {
956-
if !ct.is_conformant(&conformance_params) {
957-
return Err(crate::Error::new(
958-
"This compact list is not conformant with the given server key"
959-
.to_string(),
960-
));
961-
}
962-
}
963-
964-
unpack_and_sanitize_message_and_carries(expanded_blocks, sks, &self.info)
965-
} else {
966-
sanitize_boolean_blocks(expanded_blocks, sks, &self.info)
967-
}
968-
}
969-
IntegerCompactCiphertextListExpansionMode::NoCastingAndNoUnpacking => self
970-
.ct_list
971-
.expand_without_verification(ShortintCompactCiphertextListCastingMode::NoCasting)?,
972-
};
890+
let expanded_blocks = expansion_helper(
891+
expansion_mode,
892+
&self.ct_list,
893+
self.ct_list.proved_lists[0].0.degree,
894+
&self.info,
895+
is_packed,
896+
&crate::shortint::ciphertext::ProvenCompactCiphertextList::expand_without_verification,
897+
)?;
973898

974899
Ok(CompactCiphertextListExpander::new(
975900
expanded_blocks,

0 commit comments

Comments
 (0)