tfhe/shortint/ciphertext/
compact_list.rs

1//! Module with the definition of the Ciphertext.
2use 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    /// Expand a [`CompactCiphertextList`] to a `Vec` of [`Ciphertext`].
59    ///
60    /// The function takes a [`ShortintCompactCiphertextListCastingMode`] to indicate whether a
61    /// keyswitch should be applied during expansion, and if it does, functions can be applied as
62    /// well during casting, which can be more efficient if a refresh is required during casting.
63    ///
64    /// This is useful when using separate parameters for the public key used to encrypt the
65    /// [`CompactCiphertextList`] allowing to keyswitch to the computation params during expansion.
66    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        // No parallelism allowed
78        #[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        // Parallelism allowed
85        #[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    /// Deconstruct a [`CompactCiphertextList`] into its constituents.
174    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    /// Construct a [`CompactCiphertextList`] from its constituents.
201    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}