concrete_shortint/server_key/
sub.rs

1use super::ServerKey;
2use crate::engine::ShortintEngine;
3use crate::server_key::CheckError;
4use crate::server_key::CheckError::CarryFull;
5use crate::Ciphertext;
6
7impl ServerKey {
8    /// Homomorphically subtracts ct_right to ct_left.
9    ///
10    /// The result is returned in a _new_ ciphertext.
11    ///
12    /// This function computes the subtraction without checking
13    /// if it exceeds the capacity of the ciphertext.
14    ///
15    /// # Example
16    ///
17    /// ```rust
18    /// use concrete_shortint::gen_keys;
19    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
20    ///
21    /// // Generate the client key and the server key:
22    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
23    ///
24    /// // Encrypt two messages:
25    /// let ct_1 = cks.encrypt(2);
26    /// let ct_2 = cks.encrypt(1);
27    ///
28    /// // Compute homomorphically a subtraction:
29    /// let ct_res = sks.unchecked_sub(&ct_1, &ct_2);
30    ///
31    /// // Decrypt:
32    /// let modulus = cks.parameters.message_modulus.0 as u64;
33    /// assert_eq!(cks.decrypt(&ct_res), 2 - 1);
34    /// ```
35    pub fn unchecked_sub(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext {
36        ShortintEngine::with_thread_local_mut(|engine| {
37            engine.unchecked_sub(self, ct_left, ct_right).unwrap()
38        })
39    }
40
41    /// Homomorphically subtracts ct_right to ct_left.
42    ///
43    /// The result is assigned in the `ct_left` ciphertext.
44    ///
45    /// This function computes the subtraction without checking
46    /// if it exceeds the capacity of the ciphertext.
47    ///
48    /// # Example
49    ///
50    /// ```rust
51    /// use concrete_shortint::gen_keys;
52    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
53    ///
54    /// // Generate the client key and the server key:
55    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
56    ///
57    /// // Encrypt two messages:
58    /// let mut ct_1 = cks.encrypt(2);
59    /// let ct_2 = cks.encrypt(1);
60    ///
61    /// // Compute homomorphically a subtraction:
62    /// sks.unchecked_sub_assign(&mut ct_1, &ct_2);
63    ///
64    /// // Decrypt:
65    /// let modulus = cks.parameters.message_modulus.0 as u64;
66    /// assert_eq!(cks.decrypt(&ct_1) % modulus, 1);
67    /// ```
68    pub fn unchecked_sub_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext) {
69        ShortintEngine::with_thread_local_mut(|engine| {
70            engine
71                .unchecked_sub_assign(self, ct_left, ct_right)
72                .unwrap()
73        })
74    }
75
76    /// Verifies if ct_right can be subtracted to ct_left.
77    ///
78    /// # Example
79    ///
80    ///```rust
81    /// use concrete_shortint::gen_keys;
82    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
83    ///
84    /// // Generate the client key and the server key:
85    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
86    ///
87    /// let msg = 2;
88    ///
89    /// // Encrypt two messages:
90    /// let ct_1 = cks.encrypt(msg);
91    /// let ct_2 = cks.encrypt(msg);
92    ///
93    /// // Check if we can perform an subtraction
94    /// let can_be_subtracted = sks.is_sub_possible(&ct_1, &ct_2);
95    ///
96    /// assert_eq!(true, can_be_subtracted);
97    /// ```
98    pub fn is_sub_possible(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> bool {
99        // z = ceil( degree / 2^p ) x 2^p
100        let msg_mod = self.message_modulus.0;
101        let mut z = (ct_right.degree.0 + msg_mod - 1) / msg_mod;
102        z = z.wrapping_mul(msg_mod);
103
104        let final_operation_count = ct_left.degree.0 + z;
105
106        final_operation_count <= self.max_degree.0
107    }
108
109    /// Computes homomorphically a subtraction between two ciphertexts encrypting integer values.
110    ///
111    /// If the operation can be performed, the result is returned a _new_ ciphertext.
112    /// Otherwise [CheckError::CarryFull] is returned.
113    ///
114    /// # Example
115    ///
116    /// ```rust
117    /// use concrete_shortint::gen_keys;
118    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
119    ///
120    /// // Generate the client key and the server key:
121    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
122    ///
123    /// // Encrypt two messages:
124    /// let ct_1 = cks.encrypt(3);
125    /// let ct_2 = cks.encrypt(1);
126    ///
127    /// // Compute homomorphically a subtraction:
128    /// let ct_res = sks.checked_sub(&ct_1, &ct_2);
129    ///
130    /// assert!(ct_res.is_ok());
131    /// let modulus = cks.parameters.message_modulus.0 as u64;
132    /// let clear_res = cks.decrypt(&ct_res.unwrap());
133    /// assert_eq!(clear_res % modulus, 2);
134    /// ```
135    pub fn checked_sub(
136        &self,
137        ct_left: &Ciphertext,
138        ct_right: &Ciphertext,
139    ) -> Result<Ciphertext, CheckError> {
140        // If the ciphertexts cannot be subtracted without exceeding the degree max
141        if self.is_sub_possible(ct_left, ct_right) {
142            let ct_result = self.unchecked_sub(ct_left, ct_right);
143            Ok(ct_result)
144        } else {
145            Err(CarryFull)
146        }
147    }
148
149    /// Computes homomorphically a subtraction between two ciphertexts.
150    ///
151    /// If the operation can be performed, the result is stored in the `ct_left` ciphertext.
152    /// Otherwise [CheckError::CarryFull] is returned, and `ct_left` is not modified.
153    ///
154    /// # Example
155    ///
156    /// ```rust
157    /// use concrete_shortint::gen_keys;
158    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
159    ///
160    /// // Generate the client key and the server key:
161    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
162    ///
163    /// // Encrypt two messages:
164    /// let mut ct_1 = cks.encrypt(3);
165    /// let ct_2 = cks.encrypt(1);
166    ///
167    /// // Compute homomorphically a subtraction:
168    /// let res = sks.checked_sub_assign(&mut ct_1, &ct_2);
169    ///
170    /// assert!(res.is_ok());
171    /// let modulus = cks.parameters.message_modulus.0 as u64;
172    /// let clear_res = cks.decrypt(&ct_1);
173    /// assert_eq!(clear_res % modulus, 2);
174    /// ```
175    pub fn checked_sub_assign(
176        &self,
177        ct_left: &mut Ciphertext,
178        ct_right: &Ciphertext,
179    ) -> Result<(), CheckError> {
180        // If the ciphertexts cannot be subtracted without exceeding the degree max
181        if self.is_sub_possible(ct_left, ct_right) {
182            self.unchecked_sub_assign(ct_left, ct_right);
183            Ok(())
184        } else {
185            Err(CarryFull)
186        }
187    }
188
189    /// Computes homomorphically a subtraction between two ciphertexts.
190    ///
191    /// This checks that the subtraction is possible. In the case where the carry buffers are
192    /// full, then it is automatically cleared to allow the operation.
193    ///
194    /// # Example
195    ///
196    /// ```rust
197    /// use concrete_shortint::gen_keys;
198    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
199    ///
200    /// // Generate the client key and the server key:
201    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
202    ///
203    /// // Encrypt two messages:
204    /// let mut ct_1 = cks.encrypt(3);
205    /// let mut ct_2 = cks.encrypt(1);
206    ///
207    /// // Compute homomorphically a subtraction:
208    /// let ct_res = sks.smart_sub(&mut ct_1, &mut ct_2);
209    ///
210    /// let clear_res = cks.decrypt(&ct_res);
211    /// let modulus = cks.parameters.message_modulus.0 as u64;
212    /// assert_eq!(clear_res % modulus, 2);
213    /// ```
214    pub fn smart_sub(&self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext) -> Ciphertext {
215        ShortintEngine::with_thread_local_mut(|engine| {
216            engine.smart_sub(self, ct_left, ct_right).unwrap()
217        })
218    }
219
220    /// Computes homomorphically a subtraction between two ciphertexts.
221    ///
222    /// This checks that the subtraction is possible. In the case where the carry buffers are
223    /// full, then it is automatically cleared to allow the operation.
224    ///
225    /// # Example
226    ///
227    /// ```rust
228    /// use concrete_shortint::gen_keys;
229    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
230    ///
231    /// // Generate the client key and the server key:
232    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
233    ///
234    /// // Encrypt two messages:
235    /// let mut ct_1 = cks.encrypt(3);
236    /// let mut ct_2 = cks.encrypt(1);
237    ///
238    /// // Compute homomorphically a subtraction:
239    /// sks.smart_sub_assign(&mut ct_1, &mut ct_2);
240    /// let modulus = cks.parameters.message_modulus.0 as u64;
241    /// assert_eq!(cks.decrypt(&ct_1) % modulus, 2);
242    /// ```
243    pub fn smart_sub_assign(&self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext) {
244        ShortintEngine::with_thread_local_mut(|engine| {
245            engine.smart_sub_assign(self, ct_left, ct_right).unwrap()
246        })
247    }
248
249    /// Computes homomorphically a subtraction between two ciphertexts without checks, and returns
250    /// a correcting term.
251    ///
252    /// This checks that the subtraction is possible. In the case where the carry buffers are
253    /// full, then it is automatically cleared to allow the operation.
254    ///
255    /// # Warning
256    ///
257    /// This is an advanced functionality, needed for internal requirements.
258    pub fn unchecked_sub_with_correcting_term(
259        &self,
260        ct_left: &Ciphertext,
261        ct_right: &Ciphertext,
262    ) -> (Ciphertext, u64) {
263        ShortintEngine::with_thread_local_mut(|engine| {
264            engine
265                .unchecked_sub_with_z(self, ct_left, ct_right)
266                .unwrap()
267        })
268    }
269
270    /// Computes homomorphically a subtraction between two ciphertexts without checks, and returns
271    /// a correcting term.
272    ///
273    /// # Warning
274    ///
275    /// This is an advanced functionality, needed for internal requirements.
276    pub fn unchecked_sub_with_correcting_term_assign(
277        &self,
278        ct_left: &mut Ciphertext,
279        ct_right: &Ciphertext,
280    ) -> u64 {
281        ShortintEngine::with_thread_local_mut(|engine| {
282            engine
283                .unchecked_sub_assign_with_z(self, ct_left, ct_right)
284                .unwrap()
285        })
286    }
287
288    /// Computes homomorphically a subtraction between two ciphertexts without checks, and returns
289    /// a correcting term.
290    ///
291    /// # Warning
292    ///
293    /// This is an advanced functionality, needed for internal requirements.
294    pub fn smart_sub_with_correcting_term(
295        &self,
296        ct_left: &mut Ciphertext,
297        ct_right: &mut Ciphertext,
298    ) -> (Ciphertext, u64) {
299        ShortintEngine::with_thread_local_mut(|engine| {
300            engine.smart_sub_with_z(self, ct_left, ct_right).unwrap()
301        })
302    }
303}