tfhe/shortint/ciphertext/
compact_list.rs1use super::super::parameters::CiphertextListConformanceParams;
3use super::common::*;
4use super::standard::Ciphertext;
5use crate::conformance::ParameterSetConformant;
6use crate::core_crypto::commons::traits::ContiguousEntityContainer;
7use crate::core_crypto::entities::*;
8use crate::shortint::atomic_pattern::AtomicPattern;
9use crate::shortint::backward_compatibility::ciphertext::CompactCiphertextListVersions;
10pub use crate::shortint::parameters::ShortintCompactCiphertextListCastingMode;
11use crate::shortint::parameters::{
12 AtomicPatternKind, CarryModulus, CompactCiphertextListExpansionKind, MessageModulus,
13};
14use rayon::prelude::*;
15use serde::{Deserialize, Serialize};
16use std::fmt::Debug;
17use tfhe_versionable::Versionize;
18
19#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Versionize)]
20#[versionize(CompactCiphertextListVersions)]
21pub struct CompactCiphertextList {
22 pub ct_list: LweCompactCiphertextListOwned<u64>,
23 pub degree: Degree,
24 pub message_modulus: MessageModulus,
25 pub carry_modulus: CarryModulus,
26 pub expansion_kind: CompactCiphertextListExpansionKind,
27}
28
29impl ParameterSetConformant for CompactCiphertextList {
30 type ParameterSet = CiphertextListConformanceParams;
31
32 fn is_conformant(&self, param: &CiphertextListConformanceParams) -> bool {
33 let Self {
34 ct_list,
35 degree,
36 message_modulus,
37 carry_modulus,
38 expansion_kind,
39 } = self;
40
41 let CiphertextListConformanceParams {
42 ct_list_params,
43 message_modulus: param_message_modulus,
44 carry_modulus: param_carry_modulus,
45 degree: param_degree,
46 expansion_kind: param_expansion_kind,
47 } = param;
48
49 ct_list.is_conformant(ct_list_params)
50 && *message_modulus == *param_message_modulus
51 && *carry_modulus == *param_carry_modulus
52 && *expansion_kind == *param_expansion_kind
53 && *degree == *param_degree
54 }
55}
56
57impl CompactCiphertextList {
58 pub fn expand(
67 &self,
68 casting_mode: ShortintCompactCiphertextListCastingMode<'_>,
69 ) -> Result<Vec<Ciphertext>, crate::Error> {
70 let mut output_lwe_ciphertext_list = LweCiphertextList::new(
71 0u64,
72 self.ct_list.lwe_size(),
73 self.ct_list.lwe_ciphertext_count(),
74 self.ct_list.ciphertext_modulus(),
75 );
76
77 #[cfg(all(feature = "__wasm_api", not(feature = "parallel-wasm-api")))]
79 {
80 use crate::core_crypto::prelude::expand_lwe_compact_ciphertext_list;
81 expand_lwe_compact_ciphertext_list(&mut output_lwe_ciphertext_list, &self.ct_list);
82 }
83
84 #[cfg(any(not(feature = "__wasm_api"), feature = "parallel-wasm-api"))]
86 {
87 use crate::core_crypto::prelude::par_expand_lwe_compact_ciphertext_list;
88 par_expand_lwe_compact_ciphertext_list(&mut output_lwe_ciphertext_list, &self.ct_list);
89 }
90
91 match (self.expansion_kind, casting_mode) {
92 (
93 CompactCiphertextListExpansionKind::RequiresCasting,
94 ShortintCompactCiphertextListCastingMode::NoCasting,
95 ) => Err(crate::Error::new(String::from(
96 "Cannot expand a CompactCiphertextList that requires casting without casting, \
97 please provide a shortint::KeySwitchingKey passing it with the enum variant \
98 CompactCiphertextListExpansionMode::CastIfNecessary as casting_mode.",
99 ))),
100 (
101 CompactCiphertextListExpansionKind::RequiresCasting,
102 ShortintCompactCiphertextListCastingMode::CastIfNecessary {
103 casting_key,
104 functions,
105 },
106 ) => {
107 let functions = match functions {
108 Some(functions) => {
109 if functions.len() != output_lwe_ciphertext_list.lwe_ciphertext_count().0 {
110 return Err(crate::Error::new(format!(
111 "Cannot expand a CompactCiphertextList: got {} functions for casting, \
112 expected {}",
113 functions.len(),
114 output_lwe_ciphertext_list.lwe_ciphertext_count().0
115 )));
116 }
117 functions
118 }
119 None => &vec![None; output_lwe_ciphertext_list.lwe_ciphertext_count().0],
120 };
121
122 let atomic_pattern = casting_key.dest_server_key.atomic_pattern.kind();
123
124 let res = output_lwe_ciphertext_list
125 .par_iter()
126 .zip(functions.par_iter())
127 .flat_map(|(lwe_view, functions)| {
128 let lwe_to_cast = LweCiphertext::from_container(
129 lwe_view.as_ref().to_vec(),
130 self.ct_list.ciphertext_modulus(),
131 );
132 let shortint_ct_to_cast = Ciphertext::new(
133 lwe_to_cast,
134 self.degree,
135 NoiseLevel::UNKNOWN,
136 self.message_modulus,
137 self.carry_modulus,
138 atomic_pattern,
139 );
140
141 casting_key
142 .cast_and_apply_functions(&shortint_ct_to_cast, functions.as_deref())
143 })
144 .collect::<Vec<_>>();
145 Ok(res)
146 }
147 (CompactCiphertextListExpansionKind::NoCasting(pbs_order), _) => {
148 let res = output_lwe_ciphertext_list
149 .iter()
150 .map(|lwe_view| {
151 let ct = LweCiphertext::from_container(
152 lwe_view.as_ref().to_vec(),
153 self.ct_list.ciphertext_modulus(),
154 );
155 let atomic_pattern = AtomicPatternKind::Standard(pbs_order);
156
157 Ciphertext::new(
158 ct,
159 self.degree,
160 NoiseLevel::NOMINAL,
161 self.message_modulus,
162 self.carry_modulus,
163 atomic_pattern,
164 )
165 })
166 .collect::<Vec<_>>();
167
168 Ok(res)
169 }
170 }
171 }
172
173 pub fn into_raw_parts(
175 self,
176 ) -> (
177 LweCompactCiphertextListOwned<u64>,
178 Degree,
179 MessageModulus,
180 CarryModulus,
181 CompactCiphertextListExpansionKind,
182 ) {
183 let Self {
184 ct_list,
185 degree,
186 message_modulus,
187 carry_modulus,
188 expansion_kind,
189 } = self;
190
191 (
192 ct_list,
193 degree,
194 message_modulus,
195 carry_modulus,
196 expansion_kind,
197 )
198 }
199
200 pub fn from_raw_parts(
202 ct_list: LweCompactCiphertextListOwned<u64>,
203 degree: Degree,
204 message_modulus: MessageModulus,
205 carry_modulus: CarryModulus,
206 expansion_kind: CompactCiphertextListExpansionKind,
207 ) -> Self {
208 Self {
209 ct_list,
210 degree,
211 message_modulus,
212 carry_modulus,
213 expansion_kind,
214 }
215 }
216
217 pub fn needs_casting(&self) -> bool {
218 matches!(
219 self.expansion_kind,
220 CompactCiphertextListExpansionKind::RequiresCasting
221 )
222 }
223
224 pub fn size_elements(&self) -> usize {
225 self.ct_list.size_elements()
226 }
227
228 pub fn size_bytes(&self) -> usize {
229 self.ct_list.size_bytes()
230 }
231}