concrete_integer/server_key/crt_parallel/
scalar_sub_crt.rs

1use crate::server_key::CheckError;
2use crate::server_key::CheckError::CarryFull;
3use crate::{CrtCiphertext, ServerKey};
4use rayon::prelude::*;
5
6impl ServerKey {
7    /// Computes homomorphically a subtraction between a ciphertext and a scalar.
8    ///
9    /// This function computes the operation without checking if it exceeds the capacity of the
10    /// ciphertext.
11    ///
12    /// The result is returned as a new ciphertext.
13    ///
14    /// # Example
15    ///
16    ///```rust
17    /// use concrete_integer::gen_keys;
18    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
19    ///
20    /// // Generate the client key and the server key:
21    /// let (cks, sks) = gen_keys(&PARAM_MESSAGE_2_CARRY_2);
22    ///
23    /// let clear_1 = 14;
24    /// let clear_2 = 7;
25    /// let basis = vec![2, 3, 5];
26    /// // Encrypt two messages
27    /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
28    ///
29    /// sks.unchecked_crt_scalar_sub_assign_parallelized(&mut ctxt_1, clear_2);
30    ///
31    /// // Decrypt
32    /// let res = cks.decrypt_crt(&ctxt_1);
33    /// assert_eq!((clear_1 - clear_2) % 30, res);
34    /// ```
35    pub fn unchecked_crt_scalar_sub_parallelized(
36        &self,
37        ct: &CrtCiphertext,
38        scalar: u64,
39    ) -> CrtCiphertext {
40        let mut result = ct.clone();
41        self.unchecked_crt_scalar_sub_assign_parallelized(&mut result, scalar);
42        result
43    }
44
45    pub fn unchecked_crt_scalar_sub_assign_parallelized(
46        &self,
47        ct: &mut CrtCiphertext,
48        scalar: u64,
49    ) {
50        //Put each decomposition into a new ciphertext
51        ct.blocks
52            .par_iter_mut()
53            .zip(ct.moduli.par_iter())
54            .for_each(|(ct_i, mod_i)| {
55                let neg_scalar = (mod_i - scalar % mod_i) % mod_i;
56                self.key
57                    .unchecked_scalar_add_assign_crt(ct_i, neg_scalar as u8);
58            });
59    }
60
61    /// Computes homomorphically a subtraction of a ciphertext by a scalar.
62    ///
63    /// If the operation can be performed, the result is returned in a new ciphertext.
64    /// Otherwise [CheckError::CarryFull] is returned.
65    ///
66    /// # Example
67    ///
68    /// ```rust
69    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
70    /// use concrete_integer::gen_keys;
71    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
72    ///
73    /// // Generate the client key and the server key:
74    /// let (cks, sks) = gen_keys(&PARAM_MESSAGE_2_CARRY_2);
75    ///
76    /// let clear_1 = 14;
77    /// let clear_2 = 8;
78    /// let basis = vec![2, 3, 5];
79    ///
80    /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
81    ///
82    /// let ct_res = sks.checked_crt_scalar_sub_parallelized(&mut ctxt_1, clear_2)?;
83    ///
84    /// // Decrypt:
85    /// let dec = cks.decrypt_crt(&ct_res);
86    /// assert_eq!((clear_1 - clear_2) % 30, dec);
87    /// # Ok(())
88    /// # }
89    /// ```
90    pub fn checked_crt_scalar_sub_parallelized(
91        &self,
92        ct: &CrtCiphertext,
93        scalar: u64,
94    ) -> Result<CrtCiphertext, CheckError> {
95        if self.is_crt_scalar_sub_possible(ct, scalar) {
96            Ok(self.unchecked_crt_scalar_sub_parallelized(ct, scalar))
97        } else {
98            Err(CarryFull)
99        }
100    }
101
102    /// Computes homomorphically a subtraction of a ciphertext by a scalar.
103    ///
104    /// If the operation can be performed, the result is returned in a new ciphertext.
105    /// Otherwise [CheckError::CarryFull] is returned.
106    ///
107    /// # Example
108    ///
109    /// ```rust
110    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
111    /// use concrete_integer::gen_keys;
112    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
113    ///
114    /// // Generate the client key and the server key:
115    /// let (cks, sks) = gen_keys(&PARAM_MESSAGE_2_CARRY_2);
116    ///
117    /// let clear_1 = 14;
118    /// let clear_2 = 7;
119    /// let basis = vec![2, 3, 5];
120    ///
121    /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
122    ///
123    /// sks.checked_crt_scalar_sub_assign_parallelized(&mut ctxt_1, clear_2)?;
124    ///
125    /// // Decrypt:
126    /// let dec = cks.decrypt_crt(&ctxt_1);
127    /// assert_eq!((clear_1 - clear_2) % 30, dec);
128    /// # Ok(())
129    /// # }
130    /// ```
131    pub fn checked_crt_scalar_sub_assign_parallelized(
132        &self,
133        ct: &mut CrtCiphertext,
134        scalar: u64,
135    ) -> Result<(), CheckError> {
136        if self.is_crt_scalar_sub_possible(ct, scalar) {
137            self.unchecked_crt_scalar_sub_assign_parallelized(ct, scalar);
138            Ok(())
139        } else {
140            Err(CarryFull)
141        }
142    }
143
144    /// Computes homomorphically a subtraction of a ciphertext by a scalar.
145    ///
146    /// # Example
147    ///
148    ///```rust
149    /// use concrete_integer::gen_keys;
150    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
151    ///
152    /// // Generate the client key and the server key:
153    /// let (cks, sks) = gen_keys(&PARAM_MESSAGE_2_CARRY_2);
154    ///
155    /// let clear_1 = 14;
156    /// let clear_2 = 7;
157    /// let basis = vec![2, 3, 5];
158    /// // Encrypt two messages
159    /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
160    ///
161    /// sks.smart_crt_scalar_sub_assign_parallelized(&mut ctxt_1, clear_2);
162    ///
163    /// // Decrypt
164    /// let res = cks.decrypt_crt(&ctxt_1);
165    /// assert_eq!((clear_1 - clear_2) % 30, res);
166    /// ```
167    pub fn smart_crt_scalar_sub_parallelized(
168        &self,
169        ct: &mut CrtCiphertext,
170        scalar: u64,
171    ) -> CrtCiphertext {
172        if !self.is_crt_scalar_sub_possible(ct, scalar) {
173            self.full_extract_parallelized(ct);
174        }
175
176        self.unchecked_crt_scalar_sub_parallelized(ct, scalar)
177    }
178
179    pub fn smart_crt_scalar_sub_assign_parallelized(&self, ct: &mut CrtCiphertext, scalar: u64) {
180        if !self.is_crt_scalar_sub_possible(ct, scalar) {
181            self.full_extract_parallelized(ct);
182        }
183
184        self.unchecked_crt_scalar_sub_assign_parallelized(ct, scalar);
185    }
186}